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 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
|
||||
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
|
||||
|
|
|
@ -32,6 +32,8 @@ linters-settings:
|
|||
- w *os.File
|
||||
- to int64
|
||||
- l *ldap.Conn
|
||||
- w http.ResponseWriter
|
||||
- r *http.Request
|
||||
gci:
|
||||
sections:
|
||||
- standard
|
||||
|
|
|
@ -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))))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue