你的 ESLint 安全插件遗漏了 80% 的漏洞(我有证据)
Source: Dev.to
请提供您希望翻译的具体文本内容,我将把它翻译成简体中文并保持原有的格式、Markdown 语法以及技术术语不变。谢谢!
基准方法论
测试文件
vulnerable.js (218 行) – 包含 12 类真实漏洞
// 1. Command Injection
exec(`ls -la ${userInput}`);
execSync('echo ' + userInput);
spawn('bash', ['-c', userInput]);
// 2. Path Traversal
fs.readFile(filename, 'utf8', callback);
fs.readFileSync(filename);
// 3. Object Injection
obj[key] = value;
data[key][value] = 'test';
// 4. SQL Injection
db.query('SELECT * FROM users WHERE id = ' + userId);
// 5. Code Execution
eval(code);
new Function(code);
// 6. Regex DoS
const evilRegex = /^(a+)+$/;
new RegExp(userInput);
// 7. Weak Cryptography
crypto.createHash('md5').update(password);
Math.random().toString(36);
// 8. Timing Attacks
if (inputToken === storedToken) {
return true;
}
// 9. XSS
document.getElementById('output').innerHTML = userContent;
// 10. Insecure Cookies
document.cookie = `${name}=${value}`;
// 11. Dynamic Require
require(moduleName);
// 12. Buffer Issues
const buf = new Buffer(size);
safe-patterns.js (167 行) – 包含不应触发警告的防御模式
// Safe: Validated key access with allowlist
const VALID_KEYS = ['name', 'email', 'age'];
if (VALID_KEYS.includes(key)) {
return obj[key];
}
// Safe: hasOwnProperty check
if (Object.prototype.hasOwnProperty.call(obj, key)) {
return obj[key];
}
// Safe: Path validation with startsWith
if (!safePath.startsWith(SAFE_DIR)) throw new Error('Invalid');
fs.readFileSync(safePath);
// Safe: Timing‑safe comparison
crypto.timingSafeEqual(bufA, bufB);
// Safe: DOMPurify sanitization
const clean = DOMPurify.sanitize(userContent);
element.innerHTML = clean;
Benchmark Configuration
- Iterations: 每个测试 5 次运行
- Metrics: 平均时间、最小/最大时间、发现的问题、触发的规则
- Assumption: 运行间方差 ≤ 15 %;报告的差异 (2.83×, 3.8×) 超出此范围
Source: …
测试 1 – 公平对决(相同的 14 条规则)
首先,我仅使用两套插件中 相同的 14 条等价规则 进行测试。这确保了在相同条件下的对比。
结果
| 指标 | secure-coding | security | 胜者 |
|---|---|---|---|
| 性能 / 问题 | 24.95 ms | 25.12 ms | 🟢 secure-coding |
| 总耗时 | 723.54 ms | 527.58 ms | 🔵 security |
| 发现的问题数 | 29 | 21 | 🟢 secure-coding |
| 检测率 | 138 % | 100 % | 🟢 secure-coding |
按规则检测情况
| 规则类别 | security | secure-coding | 差异 |
|---|---|---|---|
| Timing Attacks | 1 | 5 | +4 🟢 |
| Child Process | 2 | 4 | +2 🟢 |
| Non‑literal Regexp | 1 | 3 | +2 🟢 |
| Eval / Code Execution | 1 | 2 | +1 🟢 |
| Insufficient Randomness | 0 | 1 | +1 🟢 |
| FS Path Traversal | 5 | 5 | = |
| Object Injection | 5 | 5 | = |
| Dynamic Require | 2 | 2 | = |
| Unsafe Regex | 2 | 2 | = |
| Buffer APIs | 2 | 0 | -2 🔵 |
| TOTAL | 21 | 29 | +8 |
关键发现: 在相同的规则类别下,secure-coding 发现了 38 % 更多的问题,同时每个问题的效率几乎相同。
Source: …
测试 2 – 推荐预设
接下来,我测试了每个插件的推荐配置——开箱即用的体验。
结果
| 指标 | secure-coding | security | 胜者 |
|---|---|---|---|
| 性能 / 问题 | 9.95 ms | 28.16 ms | 🟢 secure-coding |
| 总耗时 | 795.99 ms | 591.41 ms | 🔵 security |
| 发现的问题 | 80 | 21 | 🟢 secure-coding |
| 触发的规则 | 30 | 10 | 🟢 secure-coding |
| 规则总数 | 89 | 14 | 🟢 secure-coding |
检测细分
secure-coding 在 vulnerable.js 上触发的规则:
• no-unvalidated-user-input: 8 个问题
• detect-non-literal-fs-filename: 5 个问题
• detect-object-injection: 5 个问题
• no-timing-attack: 5 个问题
• detect-child-process: 4 个问题
• database-injection: 4 个问题
• no-unsafe-deserialization: 4 个问题
• no-sql-injection: 3 个问题
• detect-non-literal-regexp: 3 个问题
• no-hardcoded-credentials: 2 个问题
• detect-eval-with-expression: 2 个问题
• no-weak-crypto: 2 个问题
... 等等 18 个其他类别
security 触发的规则:
• detect-non-literal-fs-filename: 5 个问题
• detect-object-injection: 5 个问题
• detect-child-process: 2 个问题
• detect-unsafe-regex: 2 个问题
... 等等 6 个其他类别
测试 3 – 假阳性分析
这是精确度至关重要的地方。我对 safe-patterns.js(一个仅包含安全、已验证代码的文件)运行了两个插件。
结果
| 插件 | 误报数 | 精确率 |
|---|---|---|
secure-coding | 0 | 100 % |
security | 4 | 84 % |
来自 eslint-plugin-security 的 4 条误报
误报 #1 – 已验证的键访问(第 38 行)
// Pattern: Allowlist validation before access
const VALID_KEYS = ['name', 'email', 'age'];
function getField(obj, key) {
if (VALID_KEYS.includes(key)) {
return obj[key]; // ⚠️ security flags "Generic Object Injection Sink"
}
}
误报 #2 – hasOwnProperty 检查(第 45 行)
// Pattern: Property existence check before access
function safeGet(obj, key) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
return obj[key]; // ⚠️ security flags "Generic Object Injection Sink"
}
}
误报 #3 – 带 throw 的守卫语句(第 153 行)
// Pattern: Early exit guard clause
const ALLOWED_THEMES = ['light', 'dark', 'system'];
function setTheme(userTheme) {
if (!ALLOWED_THEMES.includes(userTheme)) {
throw new Error('Invalid theme');
}
config[userTheme] = true; // ⚠️ security flags "Unsafe Assignment"
}
误报 #4 – 时间安全比较(第 212 行)
// Pattern: Timing‑safe equality check
if (crypto.timingSafeEqual(bufA, bufB)) {
// safe branch
}
误报 #4:路径验证(第 107 行)
// Pattern: basename + startsWith validation
function safeReadFile(userFilename) {
const safeName = path.basename(userFilename);
const safePath = path.join(SAFE_DIR, safeName);
if (!safePath.startsWith(SAFE_DIR)) {
throw new Error('Invalid path');
}
return fs.readFileSync(safePath); // ⚠️ security flags "non literal argument"
}
该路径已完全验证:basename 去除路径遍历,startsWith 确认目录。
为什么 secure-coding 能避免这些
我们使用 基于 AST 的验证检测:
| 模式 | 检测方法 |
|---|---|
allowlist.includes(key) | 检查在外层 if 语句中是否使用 includes() |
hasOwnProperty(key) | 检查是否调用 hasOwnProperty / hasOwn |
Guard clause + throw | 检测前置的带提前退出的 IfStatement |
startsWith() 验证 | 检测路径验证模式 |
OWASP 覆盖比较
| 覆盖范围 | secure-coding | security |
|---|---|---|
| OWASP Web Top 10 | 10/10 (100 %) | ~3/10 (~30 %) |
| OWASP Mobile Top 10 | 10/10 (100 %) | 0/10 (0 %) |
| 总计 | 20/20 | ~3/20 |
LLM/AI 消息比较
安全规则正被 AI 编码助手越来越多地使用。比较以下消息:
eslint-plugin-security
Found child_process.exec() with non Literal first argument
eslint-plugin-secure-coding
🔒 CWE-78 OWASP:A03‑Injection CVSS:9.8 | Command injection detected | CRITICAL
Fix: Use execFile/spawn with {shell: false} and array args
📚 https://owasp.org/www-community/attacks/Command_Injection
| Feature | secure-coding | security |
|---|---|---|
| CWE ID | ✅ | ❌ |
| OWASP Category | ✅ | ❌ |
| CVSS Score | ✅ | ❌ |
| Fix Instructions | ✅ | ❌ |
| Documentation Link | ✅ | ❌ |
功能与文档比较
| 功能 | secure-coding | security |
|---|---|---|
| 规则总数 | 89 | 14 |
| 文档 | Comprehensive (per‑rule) → 全面(每条规则) | Basic → 基础 |
| 修复建议/规则 | 3‑6 suggestions → 3‑6 条建议 | 0 |
| CWE 引用 | ✅ All rules → ✅ 所有规则 | ❌ None → ❌ 无 |
| CVSS 分数 | ✅ Yes → ✅ 是 | ❌ No → ❌ 否 |
| OWASP 映射 | ✅ Web + Mobile | ❌ None |
| TypeScript 支持 | ✅ Full → ✅ 完整 | ⚠️ Partial → ⚠️ 部分 |
| Flat Config 支持 | ✅ Native | ✅ Native |
| 预设 | minimal, recommended, strict | recommended |
| 最近更新 | Active → 活跃 | Maintenance mode → 维护模式 |
最终判定
| 类别 | secure-coding | security | 胜者 |
|---|---|---|---|
| 性能/问题 | 9.95 ms | 28.16 ms | 🟢 secure-coding |
| 检测 | 80 个问题 | 21 个问题 | 🟢 secure-coding |
| 假阳性 | 0 | 4 | 🟢 secure-coding |
| 精确率 | 100 % | 84 % | 🟢 secure-coding |
| 规则总数 | 89 | 14 | 🟢 secure-coding |
| OWASP 覆盖率 | 20/20 | ~3/20 | 🟢 secure-coding |
| 文档 | 完整 | 基础 | 🟢 secure-coding |
| 修复建议 | 每条规则 3‑6 条 | 0 | 🟢 secure-coding |
| LLM 优化 | ⭐⭐⭐⭐⭐ | ⭐⭐ | 🟢 secure-coding |
关键洞察
- 每个问题的性能很重要 –
secure-coding在每个检测到的问题上效率提升 2.83×。 - “速度优势” = 检测差距 – 现有方案看似更快,仅因为它 漏掉 漏洞。
- 0 假阳性 – 每个标记的问题都是实际漏洞。
- 规则数量提升 6 倍 – 89 条规则对比 14 条,覆盖 Web、移动、API 和 AI 安全。
- 开发者体验 – 每条规则都包含 CWE/OWASP 引用、CVSS 分数以及 3‑6 条修复建议。
立即尝试
npm install eslint-plugin-secure-coding --save-dev
// eslint.config.js
import secureCoding from 'eslint-plugin-secure-coding';
export default [secureCoding.configs.recommended];
基准代码是开源的:
benchmark on GitHub