AYAN-AMBESH/javscan

GitHub: AYAN-AMBESH/javscan

一款用 Rust 编写的高性能 Java 静态安全测试工具,通过基于 AST 的污点分析精确检测 28 类代码安全漏洞。

Stars: 0 | Forks: 0

# javscan **高级 Java 静态应用安全测试 (SAST),使用 Rust 编写。** javscan 使用真实的 AST (tree-sitter) 解析 Java,并运行过程内**污点分析**,以追踪用户可控数据从 source(servlet 请求访问器、Spring MVC 注解参数、`main(String[] args)`、stdin)经由赋值、字符串拼接、`StringBuilder` 和 `String` 转换,最终流入危险的 sink —— 同时识别 sanitizer(OWASP Java Encoder、Apache commons-text 转义、`URLEncoder`、数字解析、`UUID.fromString`、`FilenameUtils.getName`),以降低误报率。 [sapyscan](https://github.com/AYAN-AMBESH/sapyscan) (Python SAST) 的姊妹项目。 ## 亮点 - **28 条安全规则**,附带 CWE 和 OWASP Top 10 (2021) 映射 - **基于 AST 的污点追踪**,而非正则表达式匹配 —— 带有绑定参数的 `PreparedStatement` 或 `Encode.forHtml()` 调用不会产生噪音 - **快速**:通过 rayon 进行并行扫描;约 6 万行 Java 代码只需约一秒钟 - **4 种输出格式**:彩色控制台、JSON、**SARIF 2.1.0**(兼容 GitHub Code Scanning)和自包含的交互式 **HTML 仪表板** - **基线对比**:对现有发现进行快照,然后仅针对*新*问题导致 CI 失败(指纹在行号变动后依然有效) - **内联抑制** (`// nosec`, `// javscan:ignore JS101`)、项目配置文件、严重性/置信度级别、可配置的退出代码 - 自动跳过测试源码 (`src/test`, `*Test.java`) 和构建/生成的目录 - **类型感知的 sink 匹配**和**信任边界标记**(见下文)—— 危险的*名称*不会被视为危险的*调用* ## 精确度:类型解析和信任边界 仅基于名称的匹配是 SAST 误报的主要来源。javscan 在报告之前会解析三件事: **1. 接收者的类型,而非其名称。** `.load()` 仅在接收者实际解析为 `org.yaml.snakeyaml.Yaml` 时才会触发。强化包装器 (`YamlProcessor`, `YamlPropertySourceLoader` 及其子类) 使用 `SafeConstructor` 构建其解析器,并被列入白名单。构造点会按变量进行检查,因此 `new Yaml(new SafeConstructor(...))` 是静默的,而 `new Yaml(new Constructor(...))` 是 CRITICAL。如果 `pom.xml`/`build.gradle` 声明了 SnakeYAML >= 2.0 —— 默认拒绝全局类型标签 —— 那么单纯的 `new Yaml()` 会降级为 INFO。 **2. 方法的所有者,而非其名称。** `SecurityJackson2Modules.enableDefaultTyping(mapper)` 安装了白名单 `PolymorphicTypeValidator`;它是与 `ObjectMapper#enableDefaultTyping` 不同的符号,因此不会被报告。 带有真实验证器的 `activateDefaultTyping(...)` 是 INFO(“确认白名单范围”); 而使用 `LaissezFaireSubTypeValidator` 则是 CRITICAL。 **3. 值,而非标识符。** `hardcoded-secret` 要求*值*看起来像密钥材料。 片段表示角色的名称 —— `*_TYPE`, `*_PREFIX`, `*_REGEX`, `*_REASON`, `*_HEADER`, …… —— 是领域名词,而不是凭证声明。URI、正则表达式、 命名空间前缀、标签词汇 (`Opaque`, `Bearer`) 和小写单词短语无论其熵值如何都会被拒绝; 长高熵字符串和混合字符类密码将被报告。 **信任来源。** 每个发现都带有一个 `source` 标签 —— `NETWORK`、`LOCAL_FS`、`PLUGIN`、`THEME`、`CONFIG`、`CONSTANT` 或 `UNKNOWN`。 只有 `NETWORK`(以及 `UNKNOWN`,它可能仍然是网络)保留完全的严重性; 其他级别的严重性会下降两到三级,并附带说明解释原因。一个危险的 API 读取同一个类通过 `ObjectOutputStream` 序列化的文件属于自序列化往返: 仍然会被报告,但级别为 LOW,因为要对其进行投毒需要先获得本地写入权限。针对 `SimpleEvaluationContext` 评估的 SpEL —— 它禁止了 SpEL RCE 所需的 `T(...)` 类型引用和构造函数调用 —— 完全不会被报告。 `tests/regression.rs` 将这些分别固定为正面和负面的黄金测试夹具, 因此精确度修复不会无声无息地变成召回率回归。 ## 规则 | ID | 规则 | 严重性 | CWE | |----|------|----------|-----| | JS101 | sql-injection | CRITICAL | CWE-89 | | JS102 | command-injection | CRITICAL | CWE-78 | | JS103 | ldap-injection | HIGH | CWE-90 | | JS104 | xpath-injection | HIGH | CWE-643 | | JS105 | spel-injection | CRITICAL | CWE-917 | | JS106 | script-engine-injection | CRITICAL | CWE-94 | | JS107 | log-injection | LOW | CWE-117 | | JS201 | cross-site-scripting | HIGH | CWE-79 | | JS202 | open-redirect | MEDIUM | CWE-601 | | JS203 | ssrf | HIGH | CWE-918 | | JS204 | insecure-cookie | MEDIUM | CWE-614 | | JS205 | csrf-disabled | HIGH | CWE-352 | | JS206 | permissive-cors | MEDIUM | CWE-942 | | JS207 | cleartext-http | LOW | CWE-319 | | JS301 | weak-hash (MD5/SHA-1) | HIGH | CWE-328 | | JS302 | weak-cipher (DES/RC4/ECB) | HIGH | CWE-327 | | JS303 | weak-random | LOW–HIGH | CWE-330 | | JS304 | hardcoded-crypto-material | HIGH | CWE-321 | | JS305 | trust-all-tls | CRITICAL | CWE-295 | | JS306 | weak-key-size | MEDIUM | CWE-326 | | JS401 | hardcoded-secret | HIGH–CRITICAL | CWE-798 | | JS402 | jwt-weak-signing | HIGH | CWE-347 | | JS501 | insecure-deserialization | CRITICAL | CWE-502 | | JS502 | xxe | HIGH | CWE-611 | | JS601 | path-traversal | HIGH | CWE-22 | | JS602 | zip-slip | HIGH | CWE-22 | | JS701 | redos | MEDIUM | CWE-1333 | | JS702 | unsafe-reflection | HIGH | CWE-470 | 运行 `javscan --rules` 获取完整描述。 ## 安装 ``` cargo install --path . # 或 cargo build --release # binary at target/release/javscan ``` ## 用法 ``` # 扫描项目(控制台输出) javscan src/ # 交互式 HTML 仪表板 javscan . --format html --output report.html # 用于 GitHub Code Scanning 的 SARIF javscan . --format sarif --output results.sarif # 机器可读的 JSON javscan . --format json --output results.json # 仅包含高和严重级别的发现;遇到严重级别时使 CI 失败 javscan . --min-severity high --fail-on critical # 禁用规则,排除路径,也扫描测试 javscan . --disable JS207 --disable log-injection --exclude "**/generated/**" --include-tests ``` ### 基线工作流(在现有代码库上采用 javscan) ``` javscan . --write-baseline .javscan-baseline.json # accept current findings javscan . --baseline .javscan-baseline.json # from now on: only NEW findings ``` 指纹对规则、文件和规范化的代码行进行哈希处理 —— 而不是行号 —— 因此不相关的编辑不会让基线化的发现重新出现。 ### 内联抑制 ``` Runtime.getRuntime().exec(cmd); // nosec stmt.executeQuery(sql); // javscan:ignore JS101 // javscan:ignore JS102,JS601 (a comment on the line above also applies) ``` ### 配置 —— 位于项目根目录的 `.javscan.json` ``` { "exclude": ["**/generated/**", "**/legacy/**"], "disabled_rules": ["JS207"], "min_severity": "low", "include_tests": false, "fail_on": "high" } ``` CLI 参数会覆盖配置文件。 ### 退出代码 - `0` — 没有达到或超过 `--fail-on` 阈值(默认为 `high`)的发现;使用 `--fail-on never` 可始终以 0 退出 - `1` — 存在达到/超过阈值的发现 - `2` — 执行错误(基线损坏、输出不可写等) ## 污点分析的工作原理 1. **Source** 播种污点:带有 `@RequestParam` / `@PathVariable` / `@RequestBody` / `@RequestHeader` / `@CookieValue` 注解的参数,`@GetMapping` 风格处理程序和 servlet `doGet`/`doPost` 的参数,`HttpServletRequest` 访问器 (`getParameter`, `getHeader`, `getQueryString`, ...),`main` 参数,`Scanner`/`BufferedReader` 读取。 2. **传播**会按方法运行到不动点:赋值、`+` 拼接、`StringBuilder.append/insert`、`String.format/valueOf/substring/replace/...`、三元运算、类型转换、对受污染集合的增强 for 循环,以及(启发式地)接受受污染参数的调用。 3. **Sanitizer** 清除污点:OWASP `Encode.forHtml/forJavaScript/...`、ESAPI 编码器、commons-text `escapeHtml4/escapeXml/...`、`URLEncoder.encode`、`Integer.parseInt` 及其同类、`UUID.fromString`、`FilenameUtils.getName`、`Pattern.quote`。 4. **Sink** 是特定于规则的(SQL 执行、`Runtime.exec`、响应写入器、文件构造器等...)。受污染的 sink 参数会产生高置信度的发现;动态但未经验证的拼接会在降低严重性的情况下产生中/低置信度的发现。 分析是过程内的(按方法),带有启发式调用传播 —— 这是在高扫描速度下 SAST 精确度/召回率的经典权衡。 污点分析回答的是*“这是否受攻击者控制?”*,这并不等同于*“这是否安全?”* —— 一个未受污染的值可能仍然来自本地文件、插件 描述符或主题模板。对于无论调用者如何 sink 都是危险的规则(原生反序列化、 SpEL、反射),信任来源分类器填补了这一空白, 因此这些发现是根据可达性进行排名,而不是被抑制或留在 CRITICAL 级别。 ## 示例 ``` examples/vulnerable/UserController.java 32:13 CRITICAL JS101 [sql-injection] (high confidence, CWE-89) User-controlled data reaches SQL sink `executeQuery()`; the query is attacker-influenced. > stmt.executeQuery(query); ``` `examples/` 目录包含故意设置的易受攻击和干净的文件,用作验收语料库;干净文件会产生零发现。 ## 许可证 MIT
标签:DevSecOps, LNA, Rust, SAST, 上游代理, 可视化界面, 盲注攻击, 网络流量审计, 通知系统, 静态应用安全测试