The Zed Attack Proxy (ZAP) is an open-source tool for penetration testing and security assessment of web applications. Since it can find security vulnerabilities, such as Cross-Site Scripting (XSS), SQL Injection, and Broken Authentication, by using the dynamic application security testing (DAST) approach, I wanted to try running it locally against this site.
According to NIST, a Web application security scanner is:
An automated program that searches for software security vulnerabilities within web applications.
Looks like ZAP is currently backed up by Checkmarx, while earlier it was part of the OWASP tools.
While at it, I sent accessibility feedback to Checkmarx about their front page having plenty of movement but no controls for them. No reply yet, after two weeks…
Scanning local site via Docker
First I should have the site up and running, which in my paazmaya.fi
project happens with using the command:
npm start
Then took a command from the ZAP documentation to run the full scan with Docker:
docker run --network="host" -v ${pwd}:/zap/wrk/:rw -t ghcr.io/zaproxy/zaproxy:stable zap-full-scan.py -t http://localhost:8888/ -g gen.conf -r testreport.html
However I did face an issue:
ERROR [Errno 5] ZAP failed to access: http://localhost:8888/
For some reason the localhost
could not be accessed, and even if I tried to use an IP, like in the following command:
docker run --network="host" -v ${pwd}:/zap/wrk/:rw -t ghcr.io/zaproxy/zaproxy:stable zap-full-scan.py -t http://127.0.0.1:8888/ -g gen.conf -r testreport.html
…the issue remained:
ERROR [Errno 5] ZAP failed to access: http://127.0.0.1:8888/
Turns out that the Docker Desktop setting in “Network” had the host sharing their network off, and once I turned it on, the scanner was able to access the host network.
Here is some of the output from the scanner, from which the passing parts and URLs are ommitted:
WARN-NEW: Missing Anti-clickjacking Header [10020] x 12
WARN-NEW: X-Content-Type-Options Header Missing [10021] x 11
WARN-NEW: Content Security Policy (CSP) Header Not Set [10038] x 11
WARN-NEW: PII Disclosure [10062] x 1
WARN-NEW: Permissions Policy Header Not Set [10063] x 11
WARN-NEW: Timestamp Disclosure - Unix [10096] x 1
WARN-NEW: Source Code Disclosure - SQL [10099] x 2
WARN-NEW: Private IP Disclosure [2] x 1
WARN-NEW: CORS Misconfiguration [40040] x 525
WARN-NEW: Sub Resource Integrity Attribute Missing [90003] x 11
WARN-NEW: Insufficient Site Isolation Against Spectre Vulnerability [90004] x 12
FAIL-NEW: 0 FAIL-INPROG: 0 WARN-NEW: 11 WARN-INPROG: 0 INFO: 0 IGNORE: 0 PASS: 126
Results
The final part of the Docker command ealier had -g gen.conf -r testreport.html
, which were used to create a HTML version of the report.
The HTML report contained more details, and this report summary:
Risk Level | Number of Alerts |
---|---|
High | 1 |
Medium | 5 |
Low | 5 |
Informational | 4 |
False Positives | 0 |
Let’s look at the alerts having high or medium risk level:
Name | Risk Level | Number of Instances |
---|---|---|
PII Disclosure | High | 1 |
CORS Misconfiguration | Medium | 526 |
Content Security Policy (CSP) Header Not Set | Medium | 11 |
Missing Anti-clickjacking Header | Medium | 12 |
Source Code Disclosure - SQL | Medium | 2 |
Sub Resource Integrity Attribute Missing | Medium | 11 |
The first one is interesting, the only one with high risk level and luckily only one instance. While looking at its origin, problematic-dvds-are-a-challenge
, I can already guess that this might be a false positive.
Since the blog post in question is a draft (which is has been over 10 years), it is not publivclly available and found by the scanner only because the site was running locally, where it also shows the draft posts for my own ease of use.
Property | Details |
---|---|
Risk Level | High |
Name | PII Disclosure |
Description | The response contains Personally Identifiable Information, such as CC number, SSN and similar sensitive data. |
URL | http://localhost:8888/problematic-dvds-are-a-challenge/ |
Method | GET |
Parameter | |
Attack | |
Evidence | 560 270847 270288 |
Other Info | Credit Card Type detected: Maestro |
Instances | 1 |
Solution | Check the response for the potential presence of personally identifiable information (PII), ensure nothing sensitive is leaked by the application. |
Reference | |
CWE Id | 359 |
WASC Id | 13 |
Plugin Id | 10062 |
Nice finding! The issue is however a false positive as the evidence points to an output from a DVD reader, which is not related to credit card numbers.
How about the medium risk level issues?
CORS Misconfiguration
Huh, with 526 findings it is most likely attached to any success (HTTP 200 Code) request made against the site.
Cross-Origin Resource Sharing (CORS) is a security mechanism that, uses HTTP headers to manage cross-origin requests and prevents unauthorized cross-domain access while enabling legitimate cross-origin data sharing.
This CORS misconfiguration could allow an attacker to perform AJAX queries to the vulnerable website from a malicious page loaded by the victim’s user agent.
In order to perform authenticated AJAX queries, the server must specify the header “Access-Control-Allow-Credentials: true” and the “Access-Control-Allow-Origin” header must be set to null or the malicious page’s domain. Even if this misconfiguration doesn’t allow authenticated AJAX requests, unauthenticated sensitive content can still be accessed (e.g intranet websites).
A malicious page can belong to a malicious website but also a trusted website with flaws (e.g XSS, support of HTTP without TLS allowing code injection through MITM, etc).
Adding the following header could be used to fix this issue, while allowing any access:
Access-Control-Allow-Origin: *
Or limiting access to resource only when requested via this site:
Access-Control-Allow-Origin: paazmaya.fi
Content Security Policy (CSP) Header Not Set
Another header related issue is about Content Security Policy (CSP) with 11 findings.
Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement or distribution of malware. CSP provides a set of standard HTTP headers that allow website owners to declare approved sources of content that browsers should be allowed to load on that page — covered types are JavaScript, CSS, HTML frames, fonts, images and embeddable objects such as Java applets, ActiveX, audio and video files.
This issue is not valid when the site is served in production, as the header has been configured to be:
Content-Security-Policy: frame-ancestors 'none'
Missing Anti-clickjacking Header
Still on the headers, this ClickJacking issue with 12 findings, is also handled inproduction by using the configuration:
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
The response does not protect against ‘ClickJacking’ attacks. It should include either Content-Security-Policy with ‘frame-ancestors’ directive or X-Frame-Options.
Source Code Disclosure - SQL
Two (2) instances of SQL source code were found, both are in this case false positives, since the posts are there for a purpose:
Application Source Code was disclosed by the web server. - SQL
Sub Resource Integrity Attribute Missing
Last medium risk level issue, with 11 findings, is about Subresource integrity (SRI).
The integrity attribute is missing on a script or link tag served by an external server. The integrity tag prevents an attacker who have gained access to this server from injecting a malicious content.
All the findings refer to <link rel="profile" href="https://microformats.org/profile/hcard">
which might be a bit challenging to have a validation hash that would also be kept up to date when the target page changes.
Usually SRI is used for JavaScript that will be executed in the same context as the rest of the web site. Even for CSS is might be useful, as bad behaving CSS could prevent seeing something that the user should see.
Perhaps there could be an Astro plugin (such as Astro-Shield) that generates the SRI sha256 hash for any CSS of JavaScript files in the resulting HTML?