Simulate HTTP status 429 with OWASP ZAP

Why?

When developing and testing code for Spring Data Elasticsearch I often use the OWASP ZAP proxy to monitor the data that is sent to and returned from Elasticsearch.

I now had the situation that I needed to check how the library behaves when the server returns a code 429 (too many requests) status. Rather than trying to set up a test that tries to flood my local Elasticsearch instance, I decided to add a script to ZAP that automatically for a given percentage of requests returns that status.

Add the script to ZAP

After starting ZAP, got to the Scripts tab and right-click on the proxy entry to create a new script; give the script a name, choose the script engine and the template.

Screenshot of the Scripts tab    Screenshot of the dialog to provide script details

Replace the content from the template with the following code:

// The proxyRequest and proxyResponse functions will be called for all requests  and responses made via ZAP, 
// excluding some of the automated tools
// If they return 'false' then the corresponding request / response will be dropped. 
// You can use msg.setForceIntercept(true) in either method to force a breakpoint

// Note that new proxy scripts will initially be disabled
// Right click the script in the Scripts tree and select "enable"  

/**
 * This function allows interaction with proxy requests (i.e.: outbound from the browser/client to the server).
 *
 * @param msg - the HTTP request being proxied. This is an HttpMessage object.
 */
function proxyRequest(msg) {
		// Debugging can be done using println like this
		print('proxyRequest called for url=' + msg.getRequestHeader().getURI().toString())

		return true
}

/**
 * This function allows interaction with proxy responses (i.e.: inbound from the server to the browser/client).
 *
 * @param msg - the HTTP response being proxied. This is an HttpMessage object.
 */
function proxyResponse(msg) {
		// Debugging can be done using println like this
		print('proxyResponse called for url=' + msg.getRequestHeader().getURI().toString())
		if (Math.random() < 0.25) {
				responseHeader = msg.getResponseHeader()
				responseHeader.clear()
				responseHeader.setVersion('HTTP/1.1')
				responseHeader.setStatusCode(429)
				responseHeader.setReasonPhrase('Too Many Requests')
				msg.setResponseBody('')
		}
		return true
}

After that, use the context menu to save your script and enable it, otherwise it will not be used by ZAP:

Context menu with the save and enable entries

And don’t forget to disable the script after the tests, otherwise ZAP will keep using it!