在 AppScan 中集成定制脚本,以增强 DAST 扫描
使用 AppScan 将定制脚本集成到您的 DAST 扫描中,以动态处理 HTTP 请求和响应,从而提高安全测试的灵活性和有效性。
在 AppScan 中激活定制脚本
要停用定制脚本:
- 转至工具 > 选项> 高级选项卡。
- 将 CustomScripts.Enable 设置设定为“False”。
实施和管理用于增强型 DAST 扫描的定制脚本
- 在配置设置中的高级部分下,选择定制脚本。
- 单击 + 添加按钮。
- 如有需要,可修改预填的名称字段。
- 为脚本选择适当的执行上下文::
- 请求前脚本:在发送请求前运行脚本。
- 响应后:在收到响应后运行脚本。
- 参数:用于包含多个步骤或填写表单的任务。您可以将此上下文与
setResultValue方法结合使用,以便脚本将结果返回给 AppScan。
- 在 JavaScript 字段(代码编辑器)中输入JavaScript,并使用
Ctrl+空格键在 AppScan 环境中自动完成建议。
请验证脚本的语法是否正确,并确认其与 AppScan 支持的 JavaScript 版本兼容。如需详细指导,请参阅 JavaScript 代码。
Tip: 代码编辑器会高亮显示语法错误,并通过工具提示帮助识别错误,但这些错误不会阻止脚本执行。
示例 1:可自动将登录详细信息添加到请求中,无需启用登录管理配置。
// Before each request if(request.method == "POST") { request.body = JSON.stringify({ "username": "jsmith", "password": "demo1234" }) }
示例 2:将来自响应的 API 密钥存储在全局变量中。
// 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) }示例 3:将授权 API 密钥(如果存在)附加到标头。
示例 4:添加另一个具有不同值的标题。// Before each request var authorization = environment.globalVariables.get("Authorization") if(authorization) { request.headers.set("Authorization", authorization) log(`authorization is ${authorization}`) }
在每个请求函数之前添加唯一的头部 function addUniqueHeader(headerName, value) { if(!(request.headers[headerName] != null && request.headers[headerName].includes(value))) { request.headers.add(headerName, value) } } addUniqueHeader(“headerName”,”Value”) - 单击添加以保存您的脚本。该脚本将添加到列表中并缺省启用。Note: 在 DAST 扫描期间,对每个 HTTP 请求或响应执行脚本。合理使用此功能可以提高扫描的效率和效果。在实时部署之前,在受控环境中测试脚本,以确保它们按预期运行。
- 您可以使用启用复选框,从定制脚本列表中选择启用或禁用脚本。
- 使用启用复选框,或通过在脚本列表中编辑、删除脚本或重新排序脚本来管理脚本。

- 单击开始全面扫描运行扫描。
- 结果:将针对每个请求或响应执行启用的脚本。您可以从数据 > 请求选项卡 > 请求/响应查看脚本的详细信息。Note: 缺省情况下,定制脚本在导出到模板时会进行加密。要禁用加密,请在扫描配置中将常规:加密敏感数据设置调整为 False。
AppScan 的定制脚本示例
AppScan 的定制脚本示例将上载到 GitHub 存储库。
在 AppScan 中编写有效 JavaScript 代码的准则
上下文
请求:在将请求数据发送到服务器之前修改请求数据。每个请求对象都包含了 headers、body、path 和 method 等属性,您可以根据需要对这些属性进行修改,以实现 DAST 扫描的定制。- 标头:包含所有请求标头。除缺省标头外,您可以添加、删除或修改任何标头。
// 如果不存在则添加新头;如果存在则覆盖 request.headers.set(key, value)
// 添加请求头 request.headers.add(key, value)
CAUTION: 由于脚本可能在每次请求中多次执行,建议使用set方法来添加新头信息,因为它会替换现有头信息并防止重复。仅在需要具有相同名称和不同值的多个头部时使用add方法。add方法不会添加一个已经存在相同名称和值的头。请小心避免重复标题,因为这可能会导致错误。// 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"
缺省标头(不区分大小写):这些是只读的,无法修改。- 主机:识别请求将发送到的主机。
- 内容长度:计算请求的大小,并将该信息发送到服务器。
- 正文:包含有关请求正文的信息。正文为“字符串”类型。
// Access body request.body
// Example request.body = "{ "username":"user" }"
- 路径:保存有关请求所针对的端点的信息。端点格式不包括基本 URL(例如
/api/v1/test)。该属性是只读的;即使您在运行脚本之前尝试进行更改,它仍然会与首次设置时相同。// Access url path request.path
// Example if (request.path.startsWith("api/v1/test")) - 查询:保存当前请求的查询字符串和参数(如果有)。您可以在此对象中添加或删除查询参数。每个值都被视为单个对象,如“key=value”。当您使用“getQueryString”时,它会为您提供一个字符串,其中包含用“&”符号连接的所有项目。该字符串是项目的副本,因此如果更改该字符串,也只是更改查询的副本。Note: 如果查询参数为空,AppScan 会忽略查询分隔符 (‘?’)。
// 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
- 方法:请求的方法(例如 GET/POST/等)。该属性是只读的;即使您在运行脚本之前尝试进行更改,它仍然会与首次设置时相同。
// Access to the method request.method
// Example if (request.method == "GET")
- 正文:保存请求的响应正文。响应为字符串格式,如有必要,您需要手动进行转换(例如,转换为 JSON)。该属性为只读;即使您在运行脚本前尝试修改,它也不会发生变化。
// Access body response.body
// Example let json = JSON.parse(config.response)
- 路径:包含有关响应端点的信息。
// Access to the relative url response.path
// Example if (response.path.startsWith("api/v1/test")) - 状态:存储有关响应状态的详细信息。状态是一个具有以下属性的对象:
// 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
- 标头:包含所有响应标头。除缺省标头外,您可以添加、删除或修改任何标头。
// 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"
- 父项请求:包含在响应之前发送的请求的对象。请求数据是只读的。该请求具有先前定义的请求对象的所有属性。
// Example response.request.path //- access to the path from the request
环境数据
短期数据对象会存储重要信息,直到任务结束,例如当您暂停、停止或完成扫描、登录或运行手动测试时。
- 全局变量: 全局变量数据是一种键-值数据结构,旨在存储用户特定的数据对。键是唯一的(意味着没有两个元素可以具有相同的键,尽管多个元素可以共享相同的值),这对于在运行中的脚本之间共享数据非常有用。
每次完成新扫描或重新扫描后,系统都会擦除这些数据。
// 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)
- 扫描状态:包含当前扫描的相关信息。
// determine if the current phase is explore phase environment.status.isInExplore()
// determine if the current phase is test phase environment.status.isInTest()
日志记录
在脚本中启用日志记录功能以帮助进行调试和识别问题。“onsole.log”命令在这里不起作用。相反,请使用“log”一词,后跟带引号的消息。此外,如果引擎运行期间出现与 JavaScript 语法或使用无关的错误,该错误也会记录在引擎跟踪日志中。
// Log message to file log("my cool logging") // Log message with custom source log("message", "my-cool-source")
结果
设置定制脚本执行的结果,并与“参数”上下文结合使用。AppScan 必要时将使用此结果。
// Sets the script execution result
setResultValue("result")
约束
- 避免在脚本中使用受限方法,以防脚本执行失败或出错。
- eval
- 函数(构造函数)
- setTimeout
- setInterval
使用上述任一方法都会导致脚本执行失败并产生错误。
- 遵守脚本执行限制以确保最佳性能并避免资源过度使用。
- 5 秒(上限)执行时间
- 64 MB 内存分配
只要超过其中任一限制,脚本就会失败。
错误处理
如果脚本使用任何受限制的函数并遇到错误或发生异常,将停止运行。此故障会暂停当前扫描,并将错误详细信息记录在“UserScript.log”文件中以供进一步检查。
加载配置了脚本的模板
您可以通过加载已启用脚本配置的模板来开始扫描。Program Files (x86)\HCL\AppScan Standard\Templates 中提供了一个示例模板,其中预先配置了 demo.testfire 描述文件的脚本。
AppScan 支持的 JavaScript 版本
- ES6 (2015)
- 生成器
- 尾调用
- ES8 (2017)
- 共享内存和原子操作
- ES15 (2024)
- Atomics.waitAsync
- 正则表达式标志 \v