mirror of
https://github.com/project-zot/zot.git
synced 2025-03-11 02:17:43 -05:00
test(ui): add owasp zap scanner in ci/cd (#1224)
(cherry picked from commit6d03ce5f2d
) Additional changes on top of:6d03ce5f2d
- Build and use zot from the same branch do not use a container image as scan target, use the binary - Fix typo in rules filename - Add the full rule list to the rules config file - Ignore some of the specific rules and add reasons - Add security-related headers to fix some of the issues identified by the scan - Update UI it includes the latest fixes for zap scan issues Signed-off-by: Andrei Aaron <aaaron@luxoft.com> Co-authored-by: Ramkumar Chinchani <rchincha@cisco.com>
This commit is contained in:
parent
d62c09e2cc
commit
5968e7199f
6 changed files with 158 additions and 7 deletions
66
.github/workflows/web-scan.yml
vendored
Normal file
66
.github/workflows/web-scan.yml
vendored
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
name: 'Security web scan for zot'
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
release:
|
||||||
|
types:
|
||||||
|
- published
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
zap_scan:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Scan ZOT using ZAP
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
flavor: [zot-linux-amd64-minimal, zot-linux-amd64]
|
||||||
|
steps:
|
||||||
|
- name: Install go
|
||||||
|
uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version: 1.19.x
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Build zot
|
||||||
|
run: |
|
||||||
|
echo "Building $FLAVOR"
|
||||||
|
cd $GITHUB_WORKSPACE
|
||||||
|
if [[ $FLAVOR == "zot-linux-amd64-minimal" ]]; then
|
||||||
|
make binary-minimal
|
||||||
|
else
|
||||||
|
make binary
|
||||||
|
fi
|
||||||
|
ls -l bin/
|
||||||
|
env:
|
||||||
|
FLAVOR: ${{ matrix.flavor }}
|
||||||
|
- name: Bringup zot server
|
||||||
|
run: |
|
||||||
|
# upload images, zot can serve OCI image layouts directly like so
|
||||||
|
mkdir /tmp/zot
|
||||||
|
skopeo copy --format=oci docker://busybox:latest oci:/tmp/zot/busybox:latest
|
||||||
|
# start zot
|
||||||
|
if [[ $FLAVOR == "zot-linux-amd64-minimal" ]]; then
|
||||||
|
./bin/${{ matrix.flavor }} serve examples/config-conformance.json &
|
||||||
|
else
|
||||||
|
./bin/${{ matrix.flavor }} serve examples/config-ui.json &
|
||||||
|
fi
|
||||||
|
# wait until service is up
|
||||||
|
while true; do x=0; curl -f http://localhost:8080/v2/ || x=1; if [ $x -eq 0 ]; then break; fi; sleep 1; done
|
||||||
|
env:
|
||||||
|
FLAVOR: ${{ matrix.flavor }}
|
||||||
|
- name: ZAP Scan Rest API
|
||||||
|
uses: zaproxy/action-baseline@v0.7.0
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
docker_name: 'owasp/zap2docker-stable'
|
||||||
|
target: 'http://localhost:8080/v2/'
|
||||||
|
rules_file_name: '.zap/rules.tsv'
|
||||||
|
cmd_options: '-a -j'
|
||||||
|
allow_issue_writing: false
|
||||||
|
fail_action: true
|
63
.zap/rules.tsv
Normal file
63
.zap/rules.tsv
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
# zap-baseline rule configuration file
|
||||||
|
# Change WARN to IGNORE to ignore rule or FAIL to fail if rule matches
|
||||||
|
# Only the rule identifiers are used - the names are just for info
|
||||||
|
# You can add your own messages to each rule by appending them after a tab on each line.
|
||||||
|
10003 WARN (Vulnerable JS Library (Powered by Retire.js))
|
||||||
|
10009 WARN (In Page Banner Information Leak)
|
||||||
|
10010 WARN (Cookie No HttpOnly Flag)
|
||||||
|
10011 WARN (Cookie Without Secure Flag)
|
||||||
|
10015 WARN (Re-examine Cache-control Directives)
|
||||||
|
10017 WARN (Cross-Domain JavaScript Source File Inclusion)
|
||||||
|
10019 WARN (Content-Type Header Missing)
|
||||||
|
10020 WARN (Anti-clickjacking Header)
|
||||||
|
10021 WARN (X-Content-Type-Options Header Missing)
|
||||||
|
10023 WARN (Information Disclosure - Debug Error Messages)
|
||||||
|
10024 WARN (Information Disclosure - Sensitive Information in URL)
|
||||||
|
10025 WARN (Information Disclosure - Sensitive Information in HTTP Referrer Header)
|
||||||
|
10026 WARN (HTTP Parameter Override)
|
||||||
|
10027 IGNORE (Information Disclosure - Suspicious Comments) The comments have been reviewed and will not help an attacker
|
||||||
|
10028 WARN (Open Redirect)
|
||||||
|
10029 WARN (Cookie Poisoning)
|
||||||
|
10030 WARN (User Controllable Charset)
|
||||||
|
10031 WARN (User Controllable HTML Element Attribute (Potential XSS))
|
||||||
|
10032 WARN (Viewstate)
|
||||||
|
10033 WARN (Directory Browsing)
|
||||||
|
10034 WARN (Heartbleed OpenSSL Vulnerability (Indicative))
|
||||||
|
10035 WARN (Strict-Transport-Security Header)
|
||||||
|
10036 WARN (HTTP Server Response Header)
|
||||||
|
10037 WARN (Server Leaks Information via "X-Powered-By" HTTP Response Header Field(s))
|
||||||
|
10038 WARN (Content Security Policy (CSP) Header Not Set)
|
||||||
|
10039 WARN (X-Backend-Server Header Information Leak)
|
||||||
|
10040 WARN (Secure Pages Include Mixed Content)
|
||||||
|
10041 WARN (HTTP to HTTPS Insecure Transition in Form Post)
|
||||||
|
10042 WARN (HTTPS to HTTP Insecure Transition in Form Post)
|
||||||
|
10043 WARN (User Controllable JavaScript Event (XSS))
|
||||||
|
10044 WARN (Big Redirect Detected (Potential Sensitive Information Leak))
|
||||||
|
10049 IGNORE (Content Cacheability) We'd need to set the non-cacheble headers on content which could potentially be cached
|
||||||
|
10050 WARN (Retrieved from Cache)
|
||||||
|
10052 WARN (X-ChromeLogger-Data (XCOLD) Header Information Leak)
|
||||||
|
10054 WARN (Cookie without SameSite Attribute)
|
||||||
|
10055 WARN (CSP)
|
||||||
|
10056 WARN (X-Debug-Token Information Leak)
|
||||||
|
10057 WARN (Username Hash Found)
|
||||||
|
10061 WARN (X-AspNet-Version Response Header)
|
||||||
|
10062 WARN (PII Disclosure)
|
||||||
|
10063 WARN (Permissions Policy Header Not Set)
|
||||||
|
10096 IGNORE (Timestamp Disclosure) All existing timestamps are related to container images and are required
|
||||||
|
10097 WARN (Hash Disclosure)
|
||||||
|
10098 IGNORE (Cross-Domain Misconfiguration) Cannot know in advance what DN the users will configure for CORS headers
|
||||||
|
10105 IGNORE (Weak Authentication Method) Cannot package in advance a certificate which would be used for the user's domain, so we cannot use HTTPS
|
||||||
|
10108 WARN (Reverse Tabnabbing)
|
||||||
|
10109 IGNORE (Modern Web Application) The Ajax crawler is run using -j command line option
|
||||||
|
10110 WARN (Dangerous JS Functions)
|
||||||
|
10202 WARN (Absence of Anti-CSRF Tokens)
|
||||||
|
2 WARN (Private IP Disclosure)
|
||||||
|
3 WARN (Session ID in URL Rewrite)
|
||||||
|
50001 WARN (Script Passive Scan Rules)
|
||||||
|
90001 WARN (Insecure JSF ViewState)
|
||||||
|
90002 WARN (Java Serialization Object)
|
||||||
|
90003 IGNORE (Sub Resource Integrity Attribute Missing) Google Fonts API return dynamic stylesheets depending on OS/Browser and it is not possible to use static identity hashes
|
||||||
|
90011 WARN (Charset Mismatch)
|
||||||
|
90022 WARN (Application Error Disclosure)
|
||||||
|
90030 WARN (WSDL File Detection)
|
||||||
|
90033 WARN (Loosely Scoped Cookie)
|
Can't render this file because it has a wrong number of fields in line 5.
|
2
Makefile
2
Makefile
|
@ -21,7 +21,7 @@ REGCLIENT := $(TOOLSDIR)/bin/regctl
|
||||||
REGCLIENT_VERSION := v0.4.5
|
REGCLIENT_VERSION := v0.4.5
|
||||||
ACTION_VALIDATOR := $(TOOLSDIR)/bin/action-validator
|
ACTION_VALIDATOR := $(TOOLSDIR)/bin/action-validator
|
||||||
ACTION_VALIDATOR_VERSION := v0.2.1
|
ACTION_VALIDATOR_VERSION := v0.2.1
|
||||||
ZUI_VERSION := v2.0.0-rc3
|
ZUI_VERSION := commit-1cf9b3c
|
||||||
STACKER := $(TOOLSDIR)/bin/stacker
|
STACKER := $(TOOLSDIR)/bin/stacker
|
||||||
BATS := $(TOOLSDIR)/bin/bats
|
BATS := $(TOOLSDIR)/bin/bats
|
||||||
TESTDATA := $(TOP_LEVEL)/test/data
|
TESTDATA := $(TOP_LEVEL)/test/data
|
||||||
|
|
|
@ -32,6 +32,8 @@ linters-settings:
|
||||||
- w *os.File
|
- w *os.File
|
||||||
- to int64
|
- to int64
|
||||||
- l *ldap.Conn
|
- l *ldap.Conn
|
||||||
|
- w http.ResponseWriter
|
||||||
|
- r *http.Request
|
||||||
gci:
|
gci:
|
||||||
sections:
|
sections:
|
||||||
- standard
|
- standard
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package extensions
|
package extensions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
gqlHandler "github.com/99designs/gqlgen/graphql/handler"
|
gqlHandler "github.com/99designs/gqlgen/graphql/handler"
|
||||||
|
@ -76,6 +77,14 @@ func downloadTrivyDB(cveInfo CveInfo, log log.Logger, updateInterval time.Durati
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addSearchSecurityHeaders(h http.Handler) http.HandlerFunc { //nolint:varnamelen
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func SetupSearchRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
func SetupSearchRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
||||||
repoDB repodb.RepoDB, cveInfo CveInfo, log log.Logger,
|
repoDB repodb.RepoDB, cveInfo CveInfo, log log.Logger,
|
||||||
) {
|
) {
|
||||||
|
@ -86,7 +95,7 @@ func SetupSearchRoutes(config *config.Config, router *mux.Router, storeControlle
|
||||||
|
|
||||||
extRouter := router.PathPrefix(constants.ExtSearchPrefix).Subrouter()
|
extRouter := router.PathPrefix(constants.ExtSearchPrefix).Subrouter()
|
||||||
extRouter.Methods("GET", "POST", "OPTIONS").
|
extRouter.Methods("GET", "POST", "OPTIONS").
|
||||||
Handler(gqlHandler.NewDefaultServer(gql_generated.NewExecutableSchema(resConfig)))
|
Handler(addSearchSecurityHeaders(gqlHandler.NewDefaultServer(gql_generated.NewExecutableSchema(resConfig))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,17 @@ func (uih uiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addUISecurityHeaders(h http.Handler) http.HandlerFunc { //nolint:varnamelen
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
permissionsPolicy := "microphone=(), geolocation=(), battery=(), camera=(), autoplay=(), gyroscope=(), payment=()"
|
||||||
|
w.Header().Set("Permissions-Policy", permissionsPolicy)
|
||||||
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
w.Header().Set("X-Frame-Options", "DENY")
|
||||||
|
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func SetupUIRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
func SetupUIRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
|
||||||
log log.Logger,
|
log log.Logger,
|
||||||
) {
|
) {
|
||||||
|
@ -40,11 +51,11 @@ func SetupUIRoutes(config *config.Config, router *mux.Router, storeController st
|
||||||
fsub, _ := fs.Sub(content, "build")
|
fsub, _ := fs.Sub(content, "build")
|
||||||
uih := uiHandler{log: log}
|
uih := uiHandler{log: log}
|
||||||
|
|
||||||
router.PathPrefix("/login").Handler(uih)
|
router.PathPrefix("/login").Handler(addUISecurityHeaders(uih))
|
||||||
router.PathPrefix("/home").Handler(uih)
|
router.PathPrefix("/home").Handler(addUISecurityHeaders(uih))
|
||||||
router.PathPrefix("/explore").Handler(uih)
|
router.PathPrefix("/explore").Handler(addUISecurityHeaders(uih))
|
||||||
router.PathPrefix("/image").Handler(uih)
|
router.PathPrefix("/image").Handler(addUISecurityHeaders(uih))
|
||||||
router.PathPrefix("/").Handler(http.FileServer(http.FS(fsub)))
|
router.PathPrefix("/").Handler(addUISecurityHeaders(http.FileServer(http.FS(fsub))))
|
||||||
|
|
||||||
log.Info().Msg("setting up ui routes")
|
log.Info().Msg("setting up ui routes")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue