Automate Security Testing in CI/CD with Zed Attack Proxy

Balaji Sigamani
4 min readMay 1, 2022

--

ZAP (Zed Attack Proxy) is an open source security testing tool developed and maintained by OWASP. Security is the most important aspect that often gets ignored in the CI/CD pipeline. There are static code scanning tool like white source which scans for any vulnerable dependencies within the application but this type of scanning is only passive.

Dynamic application security testing (DAST) involves testing the live application from a security perspective. Zed attack proxy (ZAP) comes under DAST, since it automatically scans for vulnerabilities in the web application by making use of the requests and responses made from the client side. It can also be used for manual penetration testing , but that wouldn’t be easy to integrate with the CI/CD pipeline. In this blog, let’s see how we can integrate automated security testing with ZAP in the pipeline.

Workflow

The ZAP tool works by scanning the HTTP responses received from the application. One way of getting this done is by starting the tool on a specific port (8080) in the machine and configure the browser with localhost:8080 as a proxy. After setting up this , we need to manually explore the application , so that all requests and responses are recorded by the tool.

The alternative and efficient way of achieving this is through automated functional testing. Instead of exploring the application manually , we can run a automated functional testing via selenium, cypress or any automated testing framework and configure the framework to use port 8080 as a proxy.

Execution

For Demo purpose I am using the OWASP Juice Shop application and run a cypress UI automation test with ZAP as a proxy.

  1. Configure cypress to use localhost:8080 as proxy
set HTTP_PROXY=http://localhost:8080
set HTTPS_PROXY=http://localhost:8080

2. Start ZAP tool in daemon mode

./zap.bat -daemon -port 8080 -host localhost

3. Execute cypress UI automation test and wait for it to complete.

npm run remote:cypress

4. Start scanning the application with ZAP. To do this, let us use the API provided by the ZAP in a python script since it will be useful in the CI/CD pipeline flow to scan and email the report.

start_scan.py

from zapv2 import ZAPv2
import time
import sendpdfreport
import os
#set up target url for scan and api key for ZAPtarget = 'https://juice-shop.herokuapp.com'
apiKey = 'mf9egge5flk6j03dnrmcn6utj6'
context_name = 'sample_context'
context_id = 1
zap = ZAPv2(apikey=apiKey, proxies={'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'})
zap.urlopen(target)
#Spider scanzap.spider.exclude_from_scan('https://juice-shop.herokuapp.com/assets.*')
scanID = zap.spider.scan(target)
while int(zap.spider.status(scanID)) < 100:
# Poll the status until it completes
print('Spider progress %: {}'.format(zap.spider.status(scanID)))
time.sleep(1)
print('Spider has completed!')
print('\n'.join(map(str, zap.spider.results(scanID))))
#Passive Scanwhile int(zap.pscan.records_to_scan) > 0:
# Loop until the passive scan has finished
print('Records to passive scan : ' + zap.pscan.records_to_scan)
time.sleep(2)
print('Passive Scan completed')
#Active ScanscanID = zap.ascan.scan(url=target)
while int(zap.ascan.status(scanID)) != 100:
print('Ascan Progress % : ' + zap.ascan.status(scanID))
time.sleep(5)
print('Active Scan completed')
#Generate report
report_path = zap.reports.generate(title='LRM ZAP Test Report',template='traditional-pdf',sites='https://juice-shop.herokuapp.com|http://juice-shop.herokuapp.com',reportdir=os.path.expanduser('~')+'\\zap-report')
print("Report is generated at : "+report_path)
#Email reportfromaddr = "XXXX@gmail.com"
toaddr = "YYYY@gmail.com"
subject = "LRM ZAP Test Report"
body = "LRM ZAP Automated Security test report"
filename = report_path
sendpdfreport.send_email_with_attachment(fromaddr,toaddr,subject,body,filename)

sendpdfreport.py

from email import encoders
from email.mime.base import MIMEBase
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import boto3
def send_email_with_attachment(fromaddr,toaddr,subject,body_text,filename):
msg = MIMEMultipart()
msg["Subject"] = subject
msg["From"] = fromaddr
msg["To"] = toaddr
# Set message body
body = MIMEText(body_text, "plain")
msg.attach(body)
#filename = "ZAP-Report.pdf" # In same directory as scriptwith open(filename, "rb") as attachment:
part = MIMEApplication(attachment.read())
part.add_header("Content-Disposition",
"attachment",
filename=filename)
msg.attach(part)
# When running the script from local machine with aws credentials file
session = boto3.Session(profile_name="XXX")
ses_client = session.client("ses", region_name="us-west-2")
#When running on build server with IAM role attached
#ses_client = boto3.client("ses", region_name="us-west-2")
# Convert message to string and send
response = ses_client.send_raw_email(
Source= fromaddr,
Destinations=[toaddr],
RawMessage={"Data": msg.as_string()}
)
print(response)

The Amazon SES (simple email service) has been used to send mail alternatively you can used google password manager to avoid email credentials to be hardcoded within the script. To know more about the API refer the documentation. The final report would like this with detailed summary, remediation of each vulnerability and it can be customizable with our own template.

Happy securing your web applications :)

Buy me a coffee :)

--

--

Responses (2)