JavaScript 数据流速查表¶
本文介绍了 JavaScript 库中通常用于变体分析和数据流查询的部分。
污点跟踪路径查询¶
使用以下模板创建污点跟踪路径查询
/**
* @kind path-problem
*/
import javascript
import DataFlow
import DataFlow::PathGraph
class MyConfig extends TaintTracking::Configuration {
MyConfig() { this = "MyConfig" }
override predicate isSource(Node node) { ... }
override predicate isSink(Node node) { ... }
override predicate isAdditionalTaintStep(Node pred, Node succ) { ... }
}
from MyConfig cfg, PathNode source, PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "taint from $@.", source.getNode(), "here"
此查询报告以下流程路径
- 从 isSource 匹配的节点开始。
- 通过变量、函数调用、属性、字符串、数组、Promise、异常和 isAdditionalTaintStep 添加的步骤进行。
- 在由 isSink 匹配的节点结束。
DataFlow 模块¶
使用数据流节点独立于语法匹配程序元素。另请参阅:“分析 JavaScript 和 TypeScript 中的数据流。”
DataFlow::
模块中的谓词
- moduleImport – 查找模块的使用
- moduleMember – 查找模块成员的使用
- globalVarRef – 查找全局变量的使用
DataFlow::
模块中的类和成员谓词
- Node – 任何可以具有值的东西,例如表达式、声明或 SSA 变量
- getALocalSource – 找到该节点的来源
- getTopLevel – 包含该节点的顶级作用域
- getFile – 包含该节点的文件
- getIntValue – 如果该节点是整数常量,则为该节点的值
- getStringValue – 如果该节点是字符串常量,则为该节点的值
- mayHaveBooleanValue – 检查值是否为
true
或false
- SourceNode 扩展 Node – 函数调用、参数、对象创建或对属性或全局变量的引用
- getALocalUse – 查找其值来自该节点的节点
- getACall – 查找以该节点为被调用者的调用
- getAnInstantiation – 查找以该节点为被调用者的
new
调用 - getAnInvocation – 查找以该节点为被调用者的调用或
new
调用 - getAMethodCall – 查找以该节点为接收者的方法调用
- getAMemberCall – 查找以该节点的成员为被调用者的调用
- getAPropertyRead – 查找以该节点为基的属性读取
- getAPropertyWrite – 查找以该节点为基的属性写入
- getAPropertySource – 查找流入该节点属性的节点
- InvokeNode、NewNode、CallNode、MethodCallNode 扩展 SourceNode – 对函数或构造函数的调用
- getArgument – 对该调用的参数
- getCalleeNode – 作为函数被调用的节点
- getCalleeName – 被调用变量或属性的名称
- getOptionArgument – 通过对象文字传入的“命名参数”
- getCallback – 作为回调传入的函数
- getACallee - 此处被调用的函数
- (MethodCallNode).getMethodName – 被调用的方法的名称
- (MethodCallNode).getReceiver – 方法调用的接收者
- FunctionNode 扩展 SourceNode – 函数定义,包括闭包、方法和类构造函数
- getName – 函数的名称,源自变量或属性名称
- getParameter – 函数的参数
- getReceiver – 代表
this
值的节点 - getAReturn – 获取返回的表达式
- ParameterNode 扩展 SourceNode – 函数的参数
- getName – 参数名称,如果有的话
- ClassNode 扩展 SourceNode – 类声明或充当类的函数
- getName – 类的名称,源自变量或属性名称
- getConstructor – 构造函数
- getInstanceMethod – 通过名称获取实例方法
- getStaticMethod – 通过名称获取静态方法
- getAnInstanceReference – 查找对类实例的引用
- getAClassReference – 查找对类的本身的引用
- ObjectLiteralNode 扩展 SourceNode – 对象文字
- getAPropertyWrite – 对象文字中的属性
- getAPropertySource – 流入属性的值
- ArrayCreationNode 扩展 SourceNode – 数组文字或对
Array
构造函数的调用 - getElement – 数组的元素
- ArrayCreationNode 扩展 SourceNode – 数组文字或对
- PropRef、PropRead、PropWrite - 读取或写入属性
- getPropertyName - 属性名称(如果为常量)
- getPropertyNameExpr - 包含属性名称的表达式
- getBase - 访问其属性的对象
- (PropWrite).getRhs - 属性赋值的右侧
StringOps 模块¶
- StringOps::Concatenation - 字符串连接,使用加号运算符、模板字面量或数组连接调用
- StringOps::StartsWith - 检查字符串是否以某些内容开头
- StringOps::EndsWith - 检查字符串是否以某些内容结尾
- StringOps::Includes - 检查字符串是否包含某些内容
- StringOps::RegExpTest - 检查字符串是否与正则表达式匹配
实用程序¶
- ExtendCall - 将属性从一个对象复制到另一个对象的调用
- JsonParserCall - 反序列化 JSON 字符串的调用
- JsonStringifyCall - 序列化 JSON 字符串的调用
- PropertyProjection - 通过名称提取嵌套属性的调用
系统和网络¶
- ClientRequest - 发出的网络请求
- DatabaseAccess - 提交到数据库的查询
- FileNameSource - 对文件名进行引用
- FileSystemAccess - 文件系统操作
- FileSystemReadAccess - 读取文件内容
- FileSystemWriteAccess - 写入文件内容
- PersistentReadAccess - 从持久性存储(如 cookie)中读取
- PersistentWriteAccess - 写入持久性存储
- SystemCommandExecution - 执行系统命令
不受信任的数据¶
- RemoteFlowSource - 不受信任的用户输入来源
- isUserControlledObject - 输入是否被反序列化为 JSON 类对象?(而不是仅仅是一个字符串)
- ClientSideRemoteFlowSource 扩展 RemoteFlowSource - 浏览器环境特有的输入
- getKind - 这是从
path
、fragment
、query
、url
还是name
派生的?
- getKind - 这是从
- HTTP::RequestInputAccess 扩展 RemoteFlowSource - 来自传入 HTTP 请求的输入
- getKind - 这是从
parameter
、header
、body
、url
还是cookie
派生的?
- getKind - 这是从
- HTTP::RequestHeaderAccess 扩展 RequestInputAccess - 访问特定标头
- getAHeaderName - 访问的标头名称
注意:某些 RemoteFlowSource 实例,例如来自 WebSocket 的输入,不属于上述任何特定子类别。
文件¶
- File、Folder 扩展 Container - 数据库中的文件或文件夹
- getBaseName - 文件或文件夹的名称
- getRelativePath - 相对于数据库根目录的路径
AST 节点¶
另请参阅:“用于处理 JavaScript 和 TypeScript 程序的抽象语法树类。”
DataFlow 和 AST 节点之间的转换
- Node.asExpr() - 将节点转换为表达式(如果可能)
- Expr.flow() - 将表达式转换为节点(始终可能)
- DataFlow::valueNode - 将表达式或声明转换为节点
- DataFlow::parameterNode - 将参数转换为节点
- DataFlow::thisNode - 获取函数的接收方节点
字符串匹配¶
- x.matches(“escape%”) - 如果 x 以“escape”开头,则成立
- x.regexpMatch(“escape.*”) - 如果 x 以“escape”开头,则成立
- x.regexpMatch(“(?i).*escape.*”) - 如果 x 包含“escape”(不区分大小写),则成立
访问路径¶
当多个属性访问链接在一起时,它们会形成所谓的“访问路径”。
要根据访问路径识别节点,请在 AccessPath 模块中使用以下谓词
- AccessPath::getAReferenceTo - 查找引用给定访问路径的节点
- AccessPath::getAnAssignmentTo - 查找分配给给定访问路径的节点
- AccessPath::getAnAliasedSourceNode - 查找引用相同访问路径的节点
getAReferenceTo
和 getAnAssignmentTo
具有用于全局访问路径的 1 参数版本,以及用于从给定节点开始的访问路径的 2 参数版本。
类型跟踪¶
另请参阅:“使用类型跟踪进行 API 建模。”
使用以下模板定义前向类型跟踪谓词
import DataFlow
SourceNode myType(TypeTracker t) {
t.start() and
result = /* SourceNode to track */
or
exists(TypeTracker t2 |
result = myType(t2).track(t2, t)
)
}
SourceNode myType() {
result = myType(TypeTracker::end())
}
使用以下模板定义后向类型跟踪谓词
import DataFlow
SourceNode myType(TypeBackTracker t) {
t.start() and
result = (/* argument to track */).getALocalSource()
or
exists(TypeBackTracker t2 |
result = myType(t2).backtrack(t2, t)
)
}
SourceNode myType() {
result = myType(TypeBackTracker::end())
}
故障排除¶
- 将调用节点用作接收器?尝试使用 getArgument 获取调用节点的参数。
- 尝试将 moduleImport 或 moduleMember 用作调用节点?尝试使用 getACall 获取对导入函数的调用,而不是函数本身。
- 由于类型不兼容而导致编译失败?确保 AST 节点和 DataFlow 节点没有混淆。使用 asExpr() 或 flow() 进行转换。
进一步阅读¶
- 使用路径查询探索数据流 在 GitHub 文档中。