定制脚本
定制脚本可以使您的 DAST 扫描更加灵活。您可以添加 JavaScript,以便在扫描过程中操纵 HTTP 请求和响应,无论是在向服务器发送请求之前还是在收到响应之后。
概述
定制脚本在 AppScan 中运行,并对内存中的请求和响应模型进行操作,使您可以通过编程方式调整请求和检查响应,而无需构建扩展或使用代理服务器。
概览
请求前:在将 HTTP 请求发送到应用程序之前执行脚本以修改该请求(添加/移除标头、加密数据、处理令牌等)。
响应后:从应用程序收到 HTTP 响应后处理该响应(解密内容、提取值等)。
参数:仅使用 JavaScript 生成多步骤操作和表单填充器的值。
合理使用此功能可以提高扫描的效率和效果。在实时部署之前,在受控环境中测试脚本,以确保它们按预期运行。
模板路径示例: C:\Program Files (x86)\HCL\AppScan Standard\Templates.
定制脚本示例:GitHub 存储库。
添加定制脚本
- 在配置设置中的高级部分下,选择定制脚本。
- 单击 + 添加按钮。
- 如有需要,可修改预填的名称字段。
- 为脚本选择适当的执行上下文::
- 请求前脚本:在发送请求前运行脚本。
- 响应后:在收到响应后运行脚本。
- 参数:用于包含多个步骤或填写表单的任务。您可以将此上下文与
setResultValue方法结合使用,以便脚本将结果返回给 AppScan。
- 在 JavaScript 字段(代码编辑器)中输入JavaScript,并使用 Ctrl+空格键在 AppScan 环境中自动完成建议。
- 单击添加以保存您的脚本。该脚本将添加到列表中并缺省启用。
- 您可以使用启用复选框,从定制脚本列表中选择启用或禁用脚本。
- 使用启用复选框,或通过在脚本列表中编辑、删除脚本或重新排序脚本来管理脚本。

- 单击开始全面扫描运行扫描。
- 结果:将针对每个请求或响应执行启用的脚本。您可以从数据 > 请求选项卡 > 请求/响应查看脚本的详细信息。
请验证脚本的语法是否正确,并确认其与 AppScan 支持的 JavaScript 版本兼容。如需详细指导,请参阅 JavaScript 代码。
注:- 定制脚本保存在扫描配置文件中,可使用模板导出。它们不包括在扫描结果中。
- 缺省情况下,在模板中导出定制脚本时,将对其进行加密。要禁用加密,请在扫描配置中将“常规:加密敏感数据”设置设为 False。
激活定制脚本
定制脚本缺省情况下处于启用状态,并在录制和扫描过程中对每个 HTTP 请求和响应执行。
要禁用脚本执行,请转到工具 > 选项 > 高级选项卡,然后将 CustomScripts.Enable 设置为“False”。
执行上下文
请求前
用途:修改传出的 HTTP 请求。
// Attach Authorization from stored global variable var token = environment.globalVariables.get("Authorization"); if (token) request.headers.set("Authorization", token);
响应后
用途:检查响应和持续值。
// Capture token from JSON response and store it for reuse
try {
var result = JSON.parse(response.body);
if (result && result.Authorization) {
environment.globalVariables.addOrUpdate("Authorization", result.Authorization);
}
} catch(e) { log(e); }参数
- 此上下文中没有可用的数据对象(请求或响应);使用它们将返回 null。
- 通过 setResultValue(value) 返回值。
在表单填充器中,当您选择值源 > 定制脚本时,列表仅显示其执行上下文为参数的脚本。
// Example: Return a unique email for registration flows
function random(n) { return Math.random().toString(36).slice(2, 2+n); }
var email = "test_" + Date.now() + "_" + random(6) + "@example.test";
setResultValue(email);API 参考文档
// Examples: // Handle headers request.headers.set("Authorization", "Bearer"); request.headers.add("X-Trace", "abc"); // Manipulate body request.body = JSON.stringify( { user:"admin" }); if(request.body.includes("admin") { ... } // Read path if (request.path.startsWith("/api/v1")) { ... } // Edit query request.query.addOrUpdate("lang","en") request.query.remove("debug") request.query.getQueryString() // Read method if (request.method == "GET") { ... }
// Examples: // Handle headers response.headers.set("Authorization", "Bearer"); response.headers.add("X-Trace", "abc"); // Read body (since it's read only) var j = JSON.parse(response.body); // Read path if (response.path.startsWith("/api/v1")) { ... } // Read response if (response.status.statusCode == 200) { ... } // Read parent request if (response.request.path.startsWith("/api/v1")) { ... }参数上下文 - 完整 API
// Update the result back to AppScan
setResultValue("ABC-" + Date.now());环境数据
短期数据仅在任务结束前可用 - 任务结束的场景包括暂停、停止或完成扫描,以及登录或结束手动测试。每次启动新扫描或重新扫描时,短期数据都会被清除。
- 全局变量: 全局变量数据是一种键-值数据结构,旨在存储用户特定的数据对。键是唯一的(意味着没有两个元素可以具有相同的键,尽管多个元素可以共享相同的值),这对于在运行中的脚本之间共享数据非常有用。
- 扫描状态:包含当前扫描的相关信息。
// Check the status of the scan environment.status.isInExplore(); environment.status.isInTest();
日志记录 - 完整 API
在脚本中启用日志记录功能以帮助进行调试和故障诊断。此环境中不支持标准 console.log 命令。相反,应改用 log 函数并传入带引号的消息,例如:log("Your message here")。如果在引擎操作期间发生与 JavaScript 语法或用法无关的运行时错误,则会将错误记录在引擎跟踪日志中,以便进一步分析。
日志将写入 AppScan 日志文件夹中的 UserScript.log 文件。
缺省情况下,该文件夹为 [UserDataFolder]\AppData\Roaming\HCL\AppScan Standard\logs。
约束和执行限制
- 受限函数:
eval, Function (constructor), setTimeout, setlnterval。如果使用了其中任何一个函数,脚本将失败。 - 限制:最长执行时间:5 秒;内存限制:64 MB。超过这些限制会导致脚本失败。
失败时扫描将暂停,详细信息将记录在 UserScript.log 中。
支持的 JavaScript 版本
- ES6:生成器、尾调用
- ES8:共享内存和原子操作
- ES15:Atomics.waitAsync、正则表达式标志 \v
自动完成中可用的对象
以下对象会显示在脚本编辑器的自动完成建议中,便于查找和使用:
- Keyword
- Array
- Date
- Object
- String
- RegExp
- JSON
- Map
- Math
脚本引擎完全支持以下对象,但它们不会显示在自动完成列表中。您仍然可以通过在编辑器中直接键入其名称来使用它们:
- ArrayBuffer
- BigInt
- Boolean
- DataView
- Error
- Iterator
- Number
- Promise
- Proxy
- Reflect
- SharedArrayBuffer
- Symbol
-
TypedArray
-
WeakMap
-
WeakRef
-
WeakSet
注: “不在自动完成中”表示编辑器不会自动建议这些项目;但是,这些对象的实现方式和行为与它们在标准 JavaScript 中完全相同。
故障诊断
- 脚本失败:检查 logs 文件夹(缺省:[UserDataFolder]\AppData\Roaming\HCL\AppScan Standard\logs),以了解有关错误的详细信息。如果遇到未经处理的异常,请将代码封装在 try...catch 块中,以便正常处理。
- 脚本未执行:确保已在配置设置中启用脚本。
如果问题与登录/授权相关,请考虑从配置 → 高级配置 → 安全包顺序中移除协商值,以防止 AppScan 自动处理这些身份验证。
请求完整 API
| 成员 | 类型 | 描述 | 示例 |
|---|---|---|---|
| headers | 对象 | 一个封装当前 HTTP 请求标头的对象,提供动态添加、更新、检索或移除标头的方法,可实现对请求元数据的精准控制。 | request.headers.set("Authorization","Bearer ...") |
| body | 字符串 | 当前 HTTP 请求的主体。 | request.body = JSON.stringify({ user:"jsmith" }) |
| path | 字符串 |
只读🔒 当前 HTTP 请求的相对路径。 |
if (request.path.startsWith("/api/v1/")) { ... } |
| query | 对象 | 包含多种方法的对象,可用于在当前 HTTP 请求中添加、更新或移除查询参数,支持对查询字符串进行动态操控。 | request.query.addOrUpdate("lang","en") request.query.remove("debug") |
| method | 字符串 |
只读🔒 当前 HTTP 请求所使用的方法。 |
if (request.method == "GET") {{ ... }} |
| 成员 | 类型 | 描述 | 示例 |
|---|---|---|---|
|
(name: string,value: string) |
空 | 将新值添加到查询字符串或更新现有值。 | request.query.addOrUpdate("appscan","appscanvalue") |
getQueryString() |
字符串 |
返回当前 HTTP 请求的完整查询字符串,包括所有参数及其值。 |
request.query.getQueryString() |
|
(name: string) |
布尔值 |
检查当前 HTTP 请求中是否存在特定查询参数。 如果参数存在,则返回 true,否则返回 false。 |
request.query.contains("lang") |
|
(name: string) |
布尔值 |
从当前 HTTP 请求中移除特定查询参数。 如果参数已移除,则返回 true,否则返回 false。 |
request.query.remove("lang") |
clear() |
空 |
从当前 HTTP 请求中移除所有查询参数。 |
request.query.clear() |
响应完整 API
| 成员 | 类型 | 描述 | 示例 |
|---|---|---|---|
| headers | 对象 | 一个封装当前 HTTP 响应标头的对象,提供动态添加、更新、检索或移除标头的方法,可实现对响应元数据的精准控制。 | response.headers.set("Authorization","Bearer ...") |
| body | 字符串 | 当前 HTTP 响应的主体。 | response.body = JSON.stringify({ user:"jsmith" }) |
| path | 字符串 |
只读🔒 当前 HTTP 响应的相对路径。 |
if (response.path.startsWith("/api/v1/")) { ... } |
| 状态 | 对象 | 表示当前 HTTP 响应状态的对象,包括状态代码和状态消息属性。 | if (response.status.code == 200) { ... } |
| request | 对象 | 表示启动响应的请求的对象。请求数据为只读,包括在前面描述的请求对象中定义的所有属性。 | if (response.request.path) { ... } |
| 成员 | 类型 | 描述 | 示例 |
|---|---|---|---|
| statusCode | 数字 |
只读🔒 当前响应的 HTTP 状态代码。 |
response.status.statusCode = 200 |
| statusDescription | 字符串 |
只读🔒 当前响应的 HTTP 状态消息。 |
response.status.statusDescription = "OK" |
| statusLine | 字符串 |
只读🔒 当前响应的 HTTP 状态行。 |
response.status.statusLine = "HTTP/1.1 200 OK" |
参数完整 API
| 成员 | 类型 | 描述 | 示例 |
|---|---|---|---|
|
(value: string) |
空 | 设置当前参数上下文脚本的结果值。 | setResultValue("ABC-" + Date.now()) |
通用对象
| 成员 | 类型 | 描述 | 示例 |
|---|---|---|---|
| items | 数组 |
只读🔒 当前 HTTP 请求中所有标头的数组。 |
|
| 成员 | 类型 | 描述 | 示例 |
|---|---|---|---|
add(name: string,value: string) |
空 |
向当前 HTTP 请求添加新标头。如果已存在具有相同名称和值的标头,则不会再次添加。 |
|
set(name: string,value: string) |
空 | 设置当前 HTTP 请求的标头。如果标头已存在,则替换其值。 |
|
|
(name: string) |
空 | 从当前 HTTP 请求中移除标头。 | request.headers.remove("Authorization")response.headers.remove("Authorization") |
| [name: string] | 字符串 | 按名称检索特定标头的值。如果标头不存在,则返回 null。 |
|
环境数据
| 成员 | 类型 | 描述 | 示例 |
|---|---|---|---|
| globalVariables | 对象 | 用于存储用户特定数据对的键值数据结构。键必须是唯一的,确保没有重复项,而多个键可以使用相同的值。此结构有助于在运行的脚本之间共享数据。 | environment.globalVariables.addOrUpdate(key, value) |
| 状态 | 对象 | 有关当前扫描状态的信息。 | environment.status.isInExplore() |
| 成员 | 类型 | 描述 | 示例 |
|---|---|---|---|
|
(key: string,value: string) |
空 | 向全局变量添加新的键值对,或更新现有键的值。 | environment.globalVariables.addOrUpdate("mycoolkey", "testValue") |
|
(key: string) |
布尔值 | 从全局变量中移除键值对。如果找到并移除了键,则返回 true,否则返回 false。 | environment.globalVariables.remove("mycoolkey") |
get(key: string) |
字符串 | 从全局变量检索特定键的值。如果键不存在,则返回空字符串。 | environment.globalVariables.get("mycoolkey") |
| 方法 | 类型 | 描述 | 示例 |
|---|---|---|---|
isInExplore() |
布尔值 | 检查扫描当前是否处于探索阶段。 | environment.status.isInExplore() |
isInTest() |
布尔值 | 检查扫描当前是否处于测试阶段。 | environment.status.isInTest() |
日志记录
| 成员 | 类型 | 描述 | 示例 |
|---|---|---|---|
log(message: string) log(message: string, source: string) |
空 | 添加具有指定消息和可选来源的新日志条目。 | log("This is a log message")
|