This blog post goes one step further, and explains how you can both explore and perform security scanning of APIs using ZAP from the command line.
This allows you to easily automate the scanning of your APIs.
Following the approach taken by the Baseline Scan we have introduced a new API scanning script which has only one dependency – Docker. You don’t need to install either ZAP or Java.
The script, zap-api-scan.py is included in the Weekly and Live ZAP Docker images, it will also be included in the next Stable image.
To use the API scanning script you just need to use the commands:
docker pull owasp/zap2docker-weekly
docker run -t owasp/zap2docker-weekly zap-api-scan.py -t \
https://www.example.com/openapi.json -f openapi
By default the script:
- Imports the API definition supplied
- Actively scans the API using a custom scan profile tuned for APIs
- Reports any issues found to the command line
If your API is particularly important or sensitive then it would be sensible to follow the scan up with a manual penetration test. You should also test the applications that use the API as data returned via the API could still be used to attack the application if it does not suitably escape data that has been originally entered via a user.
Command Line Options
The script has a number of command line options that allow it to be tuned to your requirements:
Usage: zap-api-scan.py -t <target> -f <format> [options]
-t target target API definition, OpenAPI or SOAP, local file or URL, eg https://www.example.com/openapi.json
-f format either openapi or soap
-c config_file config file to use to INFO, IGNORE or FAIL warnings
-u config_url URL of config file to use to INFO, IGNORE or FAIL warnings
-g gen_file generate default config file(all rules set to WARN)
-r report_html file to write the full ZAP HTML report
-w report_md file to write the full ZAP Wiki(Markdown) report
-x report_xml file to write the full ZAP XML report
-a include the alpha passive scan rules as well
-d show debug messages
-P specify listen port
-D delay in seconds to wait for passive scanning
-i default rules not in the config file to INFO
-l level minimum level to show: PASS, IGNORE, INFO, WARN or FAIL, use with -s to hide example URLs
-n context_file context file which will be loaded prior to scanning the target
-p progress_file progress file which specifies issues that are being addressed
-s short output format - dont show PASSes or example URLs
-z zap_options ZAP command line options e.g. -z "-config aaa=bbb -config ccc=ddd"
By default the script will use a Scan Policy tuned for APIs.
This disables rules that are focused on client side (e.g. browser) issues, such as the ones for detecting Cross Site Scripting, and also adds 2 additional rules that are implemented as scripts:
To generate a configuration file use the ‘-g’ option. This will create a file which includes all of the active and passive scan rules available: https://github.com/zaproxy/zaproxy/wiki/ZAP-API-Scan#configuration-file. You can edit this file using a text editor.
Changing a passive rule will only affect how failures are reported, but changing an active rule to IGNORE will prevent the rule from running. This is to reduce the overall scan time – passive rules are very quick while active rules can take a significant amount of time.
ZAP will use a set of default values when importing APIs. In some cases these will not be suitable values for a specific application, and therefore will not exercise enough of the code. For example a username of “test” might not cause a new user to be created as it is not a valid email address.
For APIs defined using OpenAPI/Swagger you can specify the values you want ZAP to use via ZAP command line options.
For example the options:
-config formhandler.fields.field\(0\).fieldId=username \
-config formhandler.fields.field\(0\).email@example.com \
-config formhandler.fields.field\(0\).enabled=true \
-config formhandler.fields.field\(1\).fieldId=phone \
-config formhandler.fields.field\(1\).value=012345678 \
Will supply the following values to the named fields:
username -> firstname.lastname@example.org
phone -> 012345678
Support for specifying values for APIs defined using SOAP is also planned – if you need this then get in touch with the ZAP development team and we will do our best to prioritize this.
Note that as these are ZAP command line options you will need to specify them to the script using the -z script option.
If you need to specify lots of options then you can put them all in a property file, eg called options.prop
You can then run the API scan using a command like:
docker run -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-weekly zap-api-scan.py \
-t https://www.example.com/openapi.json -f openapi \
-z "-configfile /zap/wrk/options.prop"
The "-v $(pwd):/zap/wrk/:rw" is a Docker option which maps the current working directory to a folder called /zap/wrk in the Docker instance.
Some of your APIs may be protected using authentication mechanisms.
For mechanisms that use header values we recommend that you obtain suitable tokens for your application using whatever means are appropriate and then tell ZAP to use them via another set of command line options.
For example the options:
-config replacer.full_list\(0\).description=auth1 \
-config replacer.full_list\(0\).enabled=true \
-config replacer.full_list\(0\).matchtype=REQ_HEADER \
-config replacer.full_list\(0\).matchstr=Authorization \
-config replacer.full_list\(0\).regex=false \
-config replacer.full_list\(0\).replacement=123456789 \
-config replacer.full_list\(1\).description=auth2 \
-config replacer.full_list\(1\).enabled=true \
-config replacer.full_list\(1\).matchtype=REQ_HEADER \
-config replacer.full_list\(1\).matchstr=AnotherHeader \
-config replacer.full_list\(1\).regex=false \
will cause the following headers to be added to every request ZAP makes:
You can specify as many headers as you need to by using incrementing indexes.
This functionality is provided by the Replacer add-on included by default with ZAP. It is very powerful and can do much more than just inject new header values, so if you need to manipulate the requests ZAP makes in other ways then this could be a very good option for you.
The API scanning script is an easy way for you to automate security scanning of APIs defined using OpenAPI/Swagger or SOAP.
It can be used ‘out of the box’ or quickly tuned to meet your requirements via simple command line and configuration file options.
A future blog post will explain how you can automate the security scanning of HTML based web applications in a very similar way.