不可见的 Unicode 双向字符会使源代码的显示效果与实际执行结果不一致。这就是 CVE-2021-42574 —— Trojan Source 攻击。
攻击者会嵌入可逆转文本方向的字符。在代码审查中,你看到的是:
access_level = "admin"
但编译器看到的却是:
access_level = "user"
这些字符是不可见的。你的编辑器不会显示它们,审查者也无法发现它们。bidi-guard 可以。
pip install bidi-guard
# Scan current directory recursively
bidi-guard scan .
# Scan a specific file
bidi-guard scan src/auth.py
查找所有双向 Unicode 字符,并显示它们的精确位置、上下文和严重级别。
name: BiDi Guard
on: [push, pull_request]
jobs:
bidi-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install bidi-guard
- run: bidi-guard ci .
将其添加到你的 .pre-commit-config.yaml:
repos:
- repo: https://github.com/Moshe-ship/bidi-guard
rev: v0.1.0
hooks:
- id: bidi-guard
全部 16 个 Unicode 双向控制字符:
标记为 高 或 严重 的字符可以主动重排显示文本 —— 这些正是 Trojan Source 攻击所使用的字符。
from bidi_guard import scan_file, Finding
findings = scan_file("src/auth.py")
for f in findings:
print(f"{f.char_name} at line {f.line}:{f.col} — severity: {f.severity}")
这些字符是看不见的。字面上就是看不见:
grep "RLO" file.py # finds nothing
cat file.py # looks completely normal
bidi-guard 能告诉你 grep 无法显示的信息:精确字符、位置、上下文、严重级别及其作用。它还可以通过剥离这些字符来自动修复。
MIT —— Musa the Carpenter
由 沙特 AI 社区 为您呈现 —— 优先面向阿拉伯人,进而惠及整个世界。
| 命令 | 作用 |
|---|
scan | 扫描文件中的 bidi 字符,显示带上下文的发现结果 |
ci | CI 模式 —— 若发现任何危险字符则以非零状态退出 |
fix | 从文件中移除所有 bidi 字符(默认交互式) |
explain | 通过可视化示例展示每个 bidi 字符的作用 |
init | 为你的项目生成一个 .bidi-guard.yml 配置文件 |
| 码点 | 名称 | 缩写 | 严重级别 |
|---|
| U+200E | 左到右标记 | LRM | 低 |
| U+200F | 右到左标记 | RLM | 低 |
| U+061C | 阿拉伯字母标记 | ALM | 低 |
| U+200D | 零宽连接符 | ZWJ | 低 |
| U+200C | 零宽非连接符 | ZWNJ | 低 |
| U+2066 | 左到右隔离符 | LRI | 中 |
| U+2067 | 右到左隔离符 | RLI | 高 |
| U+2068 | 首强隔离符 | FSI | 高 |
| U+2069 | 弹出方向隔离符 | PDI | 中 |
| U+202A | 左到右嵌入 | LRE | 中 |
| U+202B | 右到左嵌入 | RLE | 高 |
| U+202C | 弹出方向格式化 | 中 | |
| U+202D | 左到右覆盖 | LRO | 高 |
| U+202E | 右到左覆盖 | RLO | 严重 |
| U+2028 | 行分隔符 | LS | 中 |
| U+2029 | 段落分隔符 | PS | 中 |