rest-api-fuzz-testing
rest-api-fuzz-testing copied to clipboard
ZAP wrong endpoint URL
Running ZAP in a local deployment with the following configuration:
{
"readOnlyFileShareMounts": [
{
"fileShareName": "specifications",
"mountPath": "/specifications"
}
],
"testTasks": {
"targetConfiguration": {
"apiSpecifications": [
"/specifications/openapi.json"
],
"endpoint": "https://<endpoint-url>/managementserver/rest"
},
"tasks": [
{
"toolName": "ZAP",
"outputFolder": "zap",
"keyVaultSecrets": [
"TOKEN"
],
"authenticationMethod": {
"Token": "Token"
}
}
]
}
}
The openapi.json
specification contains the following:
"servers": [
{
"url": "https://localhost/ManagementServer/rest",
"description": "Management Server entry point"
}
]
Execution runs tests against URL from specification instead of endpoint in configuration, causing many errors like:
14529 [ZAP-Import-OpenAPI-1] WARN org.zaproxy.zap.extension.openapi.ExtensionOpenApi - Failed to access URL: https://localhost/ManagementServer/rest/cameras : java.net.ConnectException : Connection refused (Connection refused)
14529 [ZAP-Import-OpenAPI-1] WARN org.zaproxy.zap.extension.openapi.ExtensionOpenApi - Failed to access URL: https://localhost/ManagementServer/rest/cameras/id?tasks=tasks : java.net.ConnectException : Connection refused (Connection refused)
14529 [ZAP-Import-OpenAPI-1] WARN org.zaproxy.zap.extension.openapi.ExtensionOpenApi - Failed to access URL: https://localhost/ManagementServer/rest/cameras/id?task=task : java.net.ConnectException : Connection refused (Connection refused)
This happens only when using a mounted file path for the specification. Running a local python http.server on the host and changing the URL in the configuration to:
"apiSpecifications": [ "http://host.docker.internal:8000/openapi.json" ]
returns expected result. Lastly, all other tools work with:
"apiSpecifications": [ "/specifications/openapi.json" ]
@Sticcia
Hi I cannot seem to be able to repro the issue
I am using petstore swagger specification https://petstore.swagger.io/v2/swagger.json and I added the following modification
I'm using the following RAFT job configuration file:
{
"readonlyFileShareMounts": [
{
"FileShareName": "Zap-repro",
"MountPath": "/specs"
}
],
"testTasks" : {
"tasks": [
{
"toolName": "ZAP",
"outputFolder": "zap-out",
"targetConfiguration" : {
"apiSpecifications": [
"/specs/spec.json"
],
"endpoint": "https://petstore.swagger.io"
}
}
]
}
}
Hi @stishkin ,
The modification should replace your "host"
and "basePath"
as seen here: https://swagger.io/docs/specification/api-host-and-base-path/
Or, my guess is, you could try changing from "host": "petstore.swagger.io"
to "host": "localhost"
.
From what I understand, ZAP is grabbing the endpoint url from the specification (either "host"
or "servers"
) instead of the configuration. So, having the spec differ from the config should suffice to reproduce this.
(this happens only when using local mounted file, works fine if hosting i.e. Python server)
Also, I tried removing the URL altogether from the specification and got the following:
22612 [ZAP-Import-OpenAPI-1] WARN org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter - Failed to build/normalise the API URL using Server URL: /
java.lang.IllegalArgumentException: The scheme must not be null.
at org.zaproxy.zap.extension.openapi.converter.swagger.UriBuilder.validateNotNull(UriBuilder.java:279) ~[openapi-beta-19.zap:?]
at org.zaproxy.zap.extension.openapi.converter.swagger.UriBuilder.build(UriBuilder.java:252) ~[openapi-beta-19.zap:?]
at org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter.createApiUrls(SwaggerConverter.java:259) [openapi-beta-19.zap:?]
at org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter.readOpenAPISpec(SwaggerConverter.java:182) [openapi-beta-19.zap:?]
at org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter.getRequestModels(SwaggerConverter.java:159) [openapi-beta-19.zap:?]
at org.zaproxy.zap.extension.openapi.ExtensionOpenApi$1.run(ExtensionOpenApi.java:289) [openapi-beta-19.zap:?]
22612 [ZAP-Import-OpenAPI-1] WARN org.zaproxy.zap.extension.openapi.ExtensionOpenApi - Unable to obtain any server URL from the definition.
org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerException: Unable to obtain any server URL from the definition.
at org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter.createApiUrls(SwaggerConverter.java:272) ~[openapi-beta-19.zap:?]
at org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter.readOpenAPISpec(SwaggerConverter.java:182) ~[openapi-beta-19.zap:?]
at org.zaproxy.zap.extension.openapi.converter.swagger.SwaggerConverter.getRequestModels(SwaggerConverter.java:159) ~[openapi-beta-19.zap:?]
at org.zaproxy.zap.extension.openapi.ExtensionOpenApi$1.run(ExtensionOpenApi.java:289) [openapi-beta-19.zap:?]
Finally, replacing localhost
with the correct endpoint host-name does run correctly. But, since the host changes often, it should be obtained by the configuration, not the specification. Or is this a wrong assumption?
Thank you.
We are using the following Python script in order to use ZAP https://github.com/zaproxy/zaproxy/blob/main/docker/zap-api-scan.py
And we use the following flag to set the hostname
-O the hostname to override in the (remote) OpenAPI spec
There is OpenAPI add-on to ZAP that seem to expose openapitargeturl
that might support the scenario that you described in the bug:
https://www.zaproxy.org/docs/desktop/addons/openapi-support/
We need to do some investigation on how to expose that setting
I don't see why the -O
parameter will only override if targeted against a remote specification and not with a path to a local file.
I created a bug on the ZAP repository: https://github.com/zaproxy/zaproxy/issues/6673.