OWASP ZAP for DAST - EL-Kae/SAST_DAST_Tools GitHub Wiki
What is ZAP, DAST and Github Actions?
Our main DAST workflow is located here
The Zed Attack Proxy (ZAP) is a dynamic application security testing (DAST) tool that scans a live application for security vulnerabilities. This tool is similar to a vulnerability scanner but instead it focuses more on the application layer. For more information on ZAP visit their website.
DAST is testing a live web application for vulnerabilities, and is different from static application security testing (SAST) where on the source code is scanned. DAST is usually done when the development phase is completed and there is a live environment.
This is implemented in a Github action, Github's CI (continuous integration) tool, in a .yml
file. These .yml
files are stored in the .github/workflow
directory of the project's repository. Once there, the workflow only has access, and only works with, this particular source code. This is why this .yml
file needs to be placed in the repo for DAST coverage.
A .yml
file defines a workflow. A workflow has jobs, and jobs have steps. 2 jobs in a workflow will run concurrently without knowledge of each other by default. A job runs in a container spun up by Github Actions, 1 job means 1 container. This behavior can be configured to change. A step must either call another workflow from the Github marketplace using the uses
key or run a bash script with run
, then the step finishes. Once all the steps of job finishes the container of that job shutdown.
Our implementation of DAST
Below is a breakdown of our Github Action script for DAST using the ZAP Proxy tool. This is in a file named dast.yml.
Every Github action starts with the scheduler, the block of code that determines when the action runs. Then comes the actual jobs of the workflow. Only one job runs, zap-full-scan
. The secret TEST_URL
contains the target URL that ZAP will scan for vulnerabilities. This secret must be set up by the user in Github's Secret Manager for ZAP to run. The steps on how to do that is in the last section of this page.
If the secret exists a container is spun up and its public IP address is recorded. A ZAP scan will look like an attack by looking at logs. By printing the IP address used by this particular Github Action container we will be able to identify our traffic. ZAP runs with the following customized userAgent Zapped by EL-Kae
. This was also done to identify our own traffic. Once the scan is complete a .sarif
file is generated and uploaded into Github. The results of the scan can be viewed from the repo's Security tab under "Code Scanning".
If TEST_URL
does not exist the run will fail and the error message TEST_URL does not exist. Please refer to our docs https://github.com/EL-Kae/SAST_DAST_Tools/wiki/OWASP-ZAP-for-DAST#test_url-does-not-exist
will be printed out to the user.
Scheduler
As mentioned above every workflow starts with this scheduler block. The code below outlines the 3 conditions for when the workflow should run. In more recent repos main
has become the default branch name. However master
is include so this workflow can work with repos using the legacy name master
.
- This workflow will run
on
every gitpush
to themain
branch. - Or
on
pull requests
to themain
branch. workflow_dispatch
allows us to run this action from the Actions tab in the Github UI.schedule
allows us to run this action as a cron job, however this is commented out because it's not in use.
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
workflow_dispatch:
#schedule:
#- cron: '18 0 * * 4'
ZAP Job
This job uses ZAP full scan via a plugin from the Github marketplace.
jobs
indicates the beginning of the list of jobs for the workflow.- The
name
key defines the name of the job, this key will be present in all jobs. runs-on
indicates the operating system of the container. As mentioned above Github Actions creates a separate container for each job. The OS needs to be defined here. This key will also appear in all the following jobs.- steps indicates the beginning of the list of steps for the job.
- The step
Print Public IP Address
prints the IP address by creating a curl connection to the api endpointifconfig.me
. - Before ZAP runs the
if
key checks if theTEST_URL
variable exists. If it does the step runs. target
is the URL ZAP will scan.- By default, ZAP will create an issue in the repo. This is changed by
allow_issue_writing: false
. Because a sarif file is created and uploaded to Github, there is no need for a duplicate report. cmd_options
bases some flags to the ZAP tool.-j
tells ZAP to run the Ajax Spider.-z -config replacer
is a ZAP add on that replaces certain fields in an HTTP request. It is used here to replace the userAgent toZapped by the InfoSec Team
.
jobs:
zap-full-scan:
name: ZAP Full Scan
runs-on: ubuntu-latest
env:
TEST_URL: ${{ secrets.TEST_URL }}
steps:
- name: Print Pubic IP Address
run: echo "$(curl ifconfig.me)"
- name: ZAP scan step
if: env.TEST_URL != null
uses: zaproxy/[email protected]
with:
target: '${{ env.TEST_URL }}'
allow_issue_writing: false
cmd_options: >
-j -z "-config replacer.full_list(0).description=ReplaceUA
-config replacer.full_list(0).enabled=true
-config replacer.full_list(0).matchtype=REQ_HEADER
-config replacer.full_list(0).matchstr=User-Agent
-config replacer.full_list(0).regex=false
-config replacer.full_list(0).replacement=Zapped\ by\ EL-Kae"
- Once ZAP finishes, a sarif file is created using the plugin
SvanBoxel/zaproxy-to-ghas
, more info here. - The
results.sarif
file is uploaded in theUpload SARIF file
step. Please note files need to be in a .sarif format for Github to post it in the Security tab of the repo. - If the
TEST_URL
variable does not exist, the error messageTEST_URL does not exist. Please refer to the docs https://github.com/EL-Kae/SAST_DAST_Tools/wiki/OWASP-ZAP-for-DAST#test_url-does-not-exist
is printed out the user. - The library
actions/github-script@v5
allows us to create a custom error message, and highlights the message in red by usingcore.setFailed
.
- name: Create sarif file for ZAP results
if: env.TEST_URL != null
uses: SvanBoxel/zaproxy-to-ghas@main
- name: Upload SARIF file
if: env.TEST_URL != null
uses: github/codeql-action/upload-sarif@v1
with:
sarif_file: results.sarif
- name: Fail ZAP scan
if: env.TEST_URL == null
uses: actions/github-script@v5
with:
script: >
core.setFailed('file=/.github/workflows/dast.yml,line=21,col=10,endColumn=45 TEST_URL does not exist.
Please refer to our docs https://github.com/EL-Kae/SAST_DAST_Tools/wiki/OWASP-ZAP-for-DAST#test_url-does-not-exist')
DAST_URL does not exist
The DAST_WEB_URL
is a secret that contains the test URL for the application. This is the target that ZAP will scan for vulnerabilities. If you are getting this error, this means the DAST_WEB_URL
secret is missing from the Github Secrets Manager and needs to be created. Below are the steps on setting up the DAST_WEB_URL
secret. If this project is early in the development lifecycle and an environment hasn't been set up yet come back to these steps at a later time.
- From the Github repo page, go to 'Settings > Secrets > Actions' and click on the 'New repository secret' button.
- The 'Name' field should be
DAST_WEB_URL
or else this Github action will not recognize it. - The 'Value' field should contain the URL that ZAP will scan.
- Click on the green 'Add secret' button once this is done.
WARNING: The environment at the test URL will be attacked by ZAP and can cause the web application to go down. This URL should be a staging or a dev environment and not a production environment.