Custom scripts
Custom scripts can make your DAST scan more dynamic. You can add the JavaScripts to manipulate HTTP requests or responses during a scan. This can be done before a request is sent to the server or after a response is received.
How to enable custom scripts for AppScan
Custom scripts are enabled by default (CustomScripts.Enable setting is set to True).
To disable the scripts:
- Go to Tools > Options > Advanced tab.
- Set the CustomScripts.Enable setting to "False".
How to add and enable custom scripts for DAST scans
- Navigate to Custom scripts under the Advanced section of the configuration settings.
- Click the + Add button.
- The Name field is prepopulated with the date and time of script creation. You can change the name if needed.
- In the Execution context dropdown, select either Before request or After response depending on when you want the script to run.
- In the JavaScript field, enter your JavaScript code.
To receive suggestions for JavaScript code within the AppScan environment,
press Ctrl+Space.
Ensure that your code is free of syntax errors and is compatible with the version of JavaScript supported by AppScan. For more information about the rules and how to write the code, see JavaScript code.
Example 1: Add login details to your requests automatically (without using Login Management configuration).
// Before each request if(request.method == "POST") { request.body = JSON.stringify({ "username": "jsmith", "password": "demo1234" }) }
Example 2: Check if the response includes an API key and store it in the global variables.
// After each response try { var result = JSON.parse(response.body) log(`parsing: ${JSON.parse(response.body).Authorization}`) if(result.Authorization) { environment.globalVariables.addOrUpdate("Authorization", result.Authorization) log(`key = ${result.Authorization}`) } } catch (error) { log(error) }
Example 3: Set the authorization API key to the header if it exists.
// Before each request var authorization = environment.globalVariables.get("Authorization") if(authorization) { request.headers.set("Authorization", authorization) log(`authorization is ${authorization}`) }
- Click Add to save your script. The script is added to
the list and enabled by default. Note: The scripts you add are executed for each HTTP request or response during the DAST scan.Use this feature wisely to enhance the efficiency and effectiveness of your scans. Always test your scripts in a controlled environment before deploying them in a live scan to avoid any unexpected behavior or results.
- You can choose to enable or disable a script from the list of custom scripts using the Enable checkbox.
- You can modify, delete or change the order of execution of the scripts. On
the right-hand corner of the script, click
and select the option as follows:
- Edit
- Delete
- Move up
- Move down
- Click Start full scan to run the scan.
- Result: The enabled scripts are executed for each request or
response. You can view the details of the scripts from
Data > Requests tab >
Request/Response. Note: When you export custom scripts in a template, they are encrypted by default. To manually disable this encryption, from the scan configuration settings, go to Advanced Configuration and set the General: Encrypt sensitive data to False.
JavaScript code
Context
Request: You can read or modify the request data before it is sent to the server. Each request is represented by a request object, which has the following properties:- Headers: Contains all the request headers. You can add, remove or modify
any header except the default
headers.
// Add header request.headers.add(key, value)
// Override header if exist request.headers.set(key, value)
Note: Since the scripts might be executed multiple times per request, it is advisable to use theset
method to add new headers, as it replaces existing headers and prevents duplicates. Theadd
method should only be used when multiple headers with the same name are necessary, and it will not add a header if one with the same name and value already exists. Care should be taken to avoid header duplication, which can lead to errors.// Remove header request.headers.remove(key)
// Modify header request.headers[key]
// Examples request.headers.add("Authorization", "MyCoolApiKey") request.headers.set("Authorization", "SecondApiKey") request.headers.remove("Authorization") request.headers['Authorization'] = "myapikey3"
Default headers (not case-sensitive): These are read-only and cannot be modified.- Host: Identifies the host that the request is being sent to.
- Content-Length: Calculates the size of the request and sends this information to the server.
- Body: Contains information about the body of the request. The body is of
type 'string'.
// Access body request.body
// Example request.body = "{ "username":"user" }"
- Path: Holds the information about the endpoint to which the request is
intended. The endpoint format excludes the base-url (e.g.
/api/v1/test
). This property is read-only; it remains the same as when it was first set, even if you attempt to change it before running the script.// Access url path request.path
// Example if (request.path.startsWith("api/v1/test"))
- Query: Holds the query string and parameters (if there are any) for the
current request. You can add or remove query parameters from this object. Each
value is treated as a single object, like 'key=value'. When you use
'getQueryString', it gives you a string that has all the items concatenated with
an '&' sign. This string is a copy of the items, so if you change the
string, you're only changing a copy of the query.Note: If the query parameter is empty, AppScan won’t send the query delimiter (‘?’)
// Retrieve the current query string request.query.getQueryString()
// Example // Add new value (or update existing one) request.query.addOrUpdate("appscan","appscanvalue")
// Check if value exist request.query.contains("appscan") // for key only check request.query.contains("appscan=appscanvalue") // for key and value check
// Remove an item request.query.remove("appscan") // for key only check request.query.remove("appscan=appscanvalue") // for key and value check request.query.clear() // remove all values
- Method: Method of the request (e.g. GET/POST/etc). This property is
read-only; it remains the same as when it was first set, even if you attempt to
change it before running the script.
// Access to the method request.method
// Example if (request.method == "GET")
- Body: Holds the response body from the request. The response is in
string format, so you need to convert it manually if needed (to JSON for example).
// Access body response.body
// Example let json = JSON.parse(config.response)
- Path: Contains the information about the response endpoint.
// Access to the relative url response.path
// Example if (response.path.startsWith("api/v1/test"))
- Status: Stores details about the response status. The status is an
object with the following properties:
// Access status response.status.statusCode // A numeric representation of the status response.status.statusDescription // The description of the status code response.status.statusLine //the whole status line including the http version
// Example if (response.status.statusCode == 200) // check only the number if (response.status.statusDescription == "OK") // Check only the description if (response.status.statusLine == "HTTP1.1 200 OK") // Full line
- Headers: Contains all the response headers. You can add, remove or
modify any header except the default headers.
// Add header response.headers.add(key, value)
// Override header if exist response.headers.set(key, value)
// Remove header response.headers.remove(key)
// Modify header response.headers[key]
// Examples response.headers.add("Authorization", "MyCoolApiKey") response.headers.set("Authorization", "SecondApiKey") response.headers.remove("Authorization") response.headers['Authorization'] = "myapikey3"
- ParentRequest: An object that contains the request that was sent
prior to the response. The request data is read-only. The request has all
the properties as the previously defined request object.
// Example response.request.path //- access to the path from the request
Environment Data
A short-term data object stores important information until the task ends, like when you pause, stop, or complete a scan, log in, or run a manual test.
- Global variables: The global variables data is a key-value
data structure designed to store user-specific data pairs. The keys are
unique (meaning no two elements can have the same key, though
multiple elements can share the same value), which is useful for sharing
data between running scripts.
This data is erased every time a new scan or rescan is done.
// Add data to the globals or update existing one environment.globalVariables.addOrUpdate(key, value)
// Remove key data from the globals environment.globalVariables.remove(key)
// Read data - retrieves the value for the current key (without removing it) environment.globalVariables.get(key)
- Scan status: Contains information about the current scan.
// determine if the current phase is explore phase environment.status.isInExplore()
// determine if the current phase is test phase environment.status.isInTest()
Logging
Enable logging features in the script to help with debugging and identifying problems. The command 'console.log' does not function here. Instead, use the word 'log' followed by a message in quotes. Also, if there's an error during the engine's operation that is not related to JavaScript syntax or usage, this error is recorded in the engine trace log.
// Log message to file log("my cool logging") // Log message with custom source log("message", "my-cool-source")
Constraints
- eval
- Function (constructor)
- setTimeout
- setInterval
Error handling
If the script uses any restricted functions and encounters an error or exception, it stops working. This failure pauses the current scan and the error details are recorded in the ‘UserScript.log’ file for further review.
Loading template configured with scripts
You can start a scan by loading a template configured with scripts enabled. A sample template, pre-configured with scripts for the demo.testfire description file, is available at Program Files (x86)\HCL\AppScan Standard\Templates.
JavaScript versions supported by AppScan
- ES6 (2015)
- Generators
- Tail calls
- ES8 (2017)
- Shared memory and atomics
- ES15 (2024)
- Atomics.waitAsync
- Regular expression flag \v