0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-16 21:56:37 -05:00

test(ui): add owasp zap scanner in ci/cd (#1224)

(cherry picked from commit 6d03ce5f2d)

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:
Andrei Aaron 2023-02-27 21:25:47 +02:00 committed by GitHub
parent d62c09e2cc
commit 5968e7199f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 158 additions and 7 deletions

66
.github/workflows/web-scan.yml vendored Normal file
View 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
View 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.

View file

@ -21,7 +21,7 @@ REGCLIENT := $(TOOLSDIR)/bin/regctl
REGCLIENT_VERSION := v0.4.5
ACTION_VALIDATOR := $(TOOLSDIR)/bin/action-validator
ACTION_VALIDATOR_VERSION := v0.2.1
ZUI_VERSION := v2.0.0-rc3
ZUI_VERSION := commit-1cf9b3c
STACKER := $(TOOLSDIR)/bin/stacker
BATS := $(TOOLSDIR)/bin/bats
TESTDATA := $(TOP_LEVEL)/test/data

View file

@ -32,6 +32,8 @@ linters-settings:
- w *os.File
- to int64
- l *ldap.Conn
- w http.ResponseWriter
- r *http.Request
gci:
sections:
- standard

View file

@ -4,6 +4,7 @@
package extensions
import (
"net/http"
"time"
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,
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.Methods("GET", "POST", "OPTIONS").
Handler(gqlHandler.NewDefaultServer(gql_generated.NewExecutableSchema(resConfig)))
Handler(addSearchSecurityHeaders(gqlHandler.NewDefaultServer(gql_generated.NewExecutableSchema(resConfig))))
}
}

View file

@ -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,
log log.Logger,
) {
@ -40,11 +51,11 @@ func SetupUIRoutes(config *config.Config, router *mux.Router, storeController st
fsub, _ := fs.Sub(content, "build")
uih := uiHandler{log: log}
router.PathPrefix("/login").Handler(uih)
router.PathPrefix("/home").Handler(uih)
router.PathPrefix("/explore").Handler(uih)
router.PathPrefix("/image").Handler(uih)
router.PathPrefix("/").Handler(http.FileServer(http.FS(fsub)))
router.PathPrefix("/login").Handler(addUISecurityHeaders(uih))
router.PathPrefix("/home").Handler(addUISecurityHeaders(uih))
router.PathPrefix("/explore").Handler(addUISecurityHeaders(uih))
router.PathPrefix("/image").Handler(addUISecurityHeaders(uih))
router.PathPrefix("/").Handler(addUISecurityHeaders(http.FileServer(http.FS(fsub))))
log.Info().Msg("setting up ui routes")
}