Setting a Baseline for Web Security Controls

Securing modern web applications effectively is a complex process. However there are many straightforward security controls such as HTTP security headers which are very effective at blocking web common attacks.

At Mozilla we provide Security Guidelines as well as a Checklist of security controls for the developers of Firefox Services. Last year, we introduced the Mozilla Observatory, a hosted scanner to evaluate the security of websites and services. In this blog post, we present the ZAP Baseline scan designed to test the security controls of web applications in Continuous Integration and Continuous Deployment (CI/CD).

Verifying that the correct controls are in place across all of our applications can be challenging, especially in a CI/CD environment. We run full vulnerability scans against our services on a regular basis, but these can take a long time to run and are not really adapted to fast release cycles.

This is why we have introduced a ‘baseline’ scan which runs very quickly and on every release of a service, but still gives us crucial feedback about the key security controls that we are concerned about. The baseline scans are included in the CI/CD pipelines of Firefox services to inform developers of potential issues before they reach production environments. We also run it against all of those services every day to generate a dashboard of the overall security status of our services.

This blog post presents the techniques we use to implement baseline scans in our infrastructure.

The ZAP Baseline Scan

Mozilla invests heavily in the development and support of security tools. The author of this blog post leads the OWASP Zed Attack Proxy (ZAP) project,  which we use to run baseline and vulnerability scans.

The ZAP baseline scan is a quick, easy and highly configurable way to test the security controls you care about. The tests are non intrusive so they are safe to run against production applications.
You don’t need to have ZAP installed – the zap-baseline.py script uses Docker and is included in the 2 ZAP Docker images:

For our baseline scans we use the weekly docker image which has more options available – you can run the script with the -h flag to see all of them.

The script zap-baseline.py uses the ZAP spider to explore the application, by default for just one minute. Spidering the application is important to verify that all pages, and not only the top one, implement the required security controls. This is particularly useful when web frameworks will handle some of the pages automatically without setting the headers.
The script will then report all of the potential issues found.

The baseline scan can be run against an application by just specifying its URL using the -t flag:

docker run owasp/zap2docker-weekly zap-baseline.py -t https://www.example.com

This will produce output like: 

Total of 3 URLs
PASS: Cookie No HttpOnly Flag [10010]
PASS: Cookie Without Secure Flag [10011]
PASS: Password Autocomplete in Browser [10012]
PASS: Cross-Domain JavaScript Source File Inclusion [10017]
PASS: Content-Type Header Missing [10019]
PASS: Information Disclosure - Debug Error Messages [10023]
PASS: Information Disclosure - Sensitive Informations in URL [10024]
PASS: Information Disclosure - Sensitive Information in HTTP Referrer Header [10025]
PASS: HTTP Parameter Override [10026]
PASS: Information Disclosure - Suspicious Comments [10027]
PASS: Viewstate Scanner [10032]
PASS: Secure Pages Include Mixed Content [10040]
PASS: Weak Authentication Method [10105]
PASS: Absence of Anti-CSRF Tokens [10202]
PASS: Private IP Disclosure [2]
PASS: Session ID in URL Rewrite [3]
PASS: Script Passive Scan Rules [50001]
PASS: Insecure JSF ViewState [90001]
PASS: Charset Mismatch [90011]
PASS: Application Error Disclosure [90022]
PASS: WSDL File Passive Scanner [90030]
PASS: Loosely Scoped Cookie [90033]
WARN: Incomplete or No Cache-control and Pragma HTTP Header Set [10015] x 1
    https://www.example.com
WARN: Web Browser XSS Protection Not Enabled [10016] x 3
    https://www.example.com
    https://www.example.com/robots.txt
    https://www.example.com/sitemap.xml
WARN: X-Frame-Options Header Not Set [10020] x 1
    https://www.example.com
WARN: X-Content-Type-Options Header Missing [10021] x 1
    https://www.example.com
FAIL-NEW: 0    FAIL-INPROG: 0    WARN-NEW: 4    WARN-INPROG: 0    INFO: 0    IGNORE: 0    PASS: 22

By default the output lists all of the passive scan rules applied and whether they passed or failed.

You can change how the baseline handles different errors by specifying a rule configuration file via either the -c flag (for a local file) or the -u flag for a remote URL.
You can also generate a default file using the ‘g’ option: https://github.com/zaproxy/community-scripts/blob/master/api/mass-baseline/mass-baseline-default.conf
As specified in the generated file header you can change any of the “WARN”s to “IGNORE” or “FAIL”.

The script will exit with a 0 if there are no issues, 1 if there are any failures or 2 if there are just warnings. The return value can therefore be used in CI tools like Jenkins, CircleCI, TravisCI, etc. to fail a build step.

For example, the configuration below shows how the baseline scan can run in CircleCI with every pull request:

test:
  override:
    # build and run an application container
    - docker build -t myrepo/myapp
    - docker run myrepo/myapp &
    # retrieve the ZAP container
    - docker pull owasp/zap2docker-weekly
    # run the baseline scan against the application
    - |
      docker run -t owasp/zap2docker-weekly zap-baseline.py \
      -t http://172.17.0.2:8080/ -m 3 -i

Scanning Multiple Sites

The baseline scan is a great way to check that a single site meets your base security requirements.

In order to run the ZAP Baseline scan against a large number of websites, we have written a set of wrapper scripts specific to Mozilla. You can find  generic versions of these scripts in the ZAP community-scripts repository.

You will need to customize these scripts as detailed in the README:

  • Change the sites listed in mass-baseline.sh
  • Change the relevant user and repo details in mass-baseline.sh
  • Build a docker image
  • Run the docker image, setting the credentials for your user

These scripts will then generate a summary dashboard in your repo wiki:

Baseline-summary
The ‘Status’ badge is a link to a page containing the latest baseline results for the relevant application and the ‘History’ date links to a page which show all of the previous scans.
Example pages are included on the community scripts wiki: https://github.com/zaproxy/community-scripts/wiki/Baseline-Summary

Tuning

The baseline scan is highly configurable and allows you to fine tune the scanning to handle your applications more effectively.
You can do things like:

  • Increase the time spent spidering your application
  • Use the Ajax Spider in addition to the standard ZAP spider to handle applications that make heavy use of JavaScript
  • Include alpha passive scan rules as well as the beta and release quality ones used by default
  • Ignore specific URLs or even ignore specific issues on those pages
  • Link known issues to a bugtracker URL
  • Specify any of the options supported on the ZAP command line

For more details see the ZAP wiki: https://github.com/zaproxy/zaproxy/wiki/ZAP-Baseline-Scan

Conclusion

The baseline scan gives us immediate feedback about the security controls in place across all of our web applications. The scans run on every commit so that we are immediately aware if there has been any regression. The dashboard allows us to track the state of our applications and the CI integration provides the ability to block a deployment if the baseline is not met.

Integrating baseline scanning in CI/CD helps us work more closely with developers and operators. We don’t force our security tools onto DevOps processes, we integrate security into DevOps. The net effect is better collaboration between teams, and faster turnaround on fixing security issues.