介绍
# Security Audit
扫描、检测并修复代码库和基础设施中的安全问题。涵盖依赖漏洞、密钥检测、OWASP Top 10、SSL/TLS 验证、文件权限以及安全编码模式。
## 何时使用
- 扫描项目依赖中的已知漏洞 - 在源代码中检测硬编码的密钥、API 密钥或凭证 - 审查代码中的 OWASP Top 10 漏洞(注入、XSS、CSRF 等) - 验证端点的 SSL/TLS 配置 - 审计文件和目录权限 - 检查身份验证和授权模式 - 准备进行安全审查或合规性审计
## 依赖漏洞扫描
### Node.js
```bash # Built-in npm audit npm audit npm audit --json | jq '.vulnerabilities | to_entries[] | {name: .key, severity: .value.severity, via: .value.via[0]}'
# Fix automatically where possible npm audit fix
# Show only high and critical npm audit --audit-level=high
# Check a specific package npm audit --package-lock-only
# Alternative: use npx to scan without installing npx audit-ci --high ```
### Python
```bash # pip-audit (recommended) pip install pip-audit pip-audit pip-audit -r requirements.txt pip-audit --format=json
# safety (alternative) pip install safety safety check safety check -r requirements.txt --json
# Check a specific package pip-audit --requirement=- <<< "requests==2.25.0" ```
### Go
```bash # Built-in vuln checker go install golang.org/x/vuln/cmd/govulncheck@latest govulncheck ./...
# Check specific binary govulncheck -mode=binary ./myapp ```
### Rust
```bash # cargo-audit cargo install cargo-audit cargo audit
# With fix suggestions cargo audit fix ```
### 通用:Trivy(扫描任何项目)
```bash # Install: https://aquasecurity.github.io/trivy # Scan filesystem trivy fs .
# Scan specific language trivy fs --scanners vuln --severity HIGH,CRITICAL .
# Scan Docker image trivy image myapp:latest
# JSON output trivy fs --format json -o results.json . ```
## 密钥检测
### 手动 grep 模式
```bash # AWS keys grep -rn 'AKIA[0-9A-Z]\{16\}' --include='*.{js,ts,py,go,java,rb,env,yml,yaml,json,xml,cfg,conf,ini}' .
# Generic API keys and tokens grep -rn -i 'api[_-]\?key\|api[_-]\?secret\|access[_-]\?token\|auth[_-]\?token\|bearer ' \ --include='*.{js,ts,py,go,java,rb,env,yml,yaml,json}' .
# Private keys grep -rn 'BEGIN.*PRIVATE KEY' .
# Passwords in config grep -rn -i 'password\s*[:=]' --include='*.{env,yml,yaml,json,xml,cfg,conf,ini,toml}' .
# Connection strings with credentials grep -rn -i 'mongodb://\|mysql://\|postgres://\|redis://' --include='*.{js,ts,py,go,env,yml,yaml,json}' . | grep -v 'localhost\|127.0.0.1\|example'
# JWT tokens (three base64 segments separated by dots) grep -rn 'eyJ[A-Za-z0-9_-]*\.eyJ[A-Za-z0-9_-]*\.' --include='*.{js,ts,py,go,log,json}' . ```
### 使用 git 进行自动扫描
```bash # Scan git history for secrets (not just current files) # Using git log + grep git log -p --all | grep -n -i 'api.key\|password\|secret\|token' | head -50
# Check staged files before commit git diff --cached --name-only | xargs grep -l -i 'api.key\|password\|secret\|token' 2>/dev/null ```
### 密钥预提交钩子
```bash #!/bin/bash # .git/hooks/pre-commit - Block commits containing potential secrets
PATTERNS=( 'AKIA[0-9A-Z]{16}' 'BEGIN.*PRIVATE KEY' 'password\s*[:=]\s*["\x27][^"\x27]+' 'api[_-]?key\s*[:=]\s*["\x27][^"\x27]+' 'sk-[A-Za-z0-9]{20,}' 'ghp_[A-Za-z0-9]{36}' 'xox[bpoas]-[A-Za-z0-9-]+' )
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM) [ -z "$STAGED_FILES" ] && exit 0
EXIT_CODE=0 for pattern in "${PATTERNS[@]}"; do matches=$(echo "$STAGED_FILES" | xargs grep -Pn "$pattern" 2>/dev/null) if [ -n "$matches" ]; then echo "BLOCKED: Potential secret detected matching pattern: $pattern" echo "$matches" EXIT_CODE=1 fi done
if [ $EXIT_CODE -ne 0 ]; then echo "" echo "To proceed anyway: git commit --no-verify" echo "To remove secrets: replace with environment variables" fi exit $EXIT_CODE ```
### .gitignore 审计
```bash # Check if sensitive files are tracked echo "--- Files that should probably be gitignored ---" for pattern in '.env' '.env.*' '*.pem' '*.key' '*.p12' '*.pfx' 'credentials.json' \ 'service-account*.json' '*.keystore' 'id_rsa' 'id_ed25519'; do found=$(git ls-files "$pattern" 2>/dev/null) [ -n "$found" ] && echo " TRACKED: $found" done
# Check if .gitignore exists and has common patterns if [ ! -f .gitignore ]; then echo "WARNING: No .gitignore file found" else for entry in '.env' 'node_modules' '*.key' '*.pem'; do grep -q "$entry" .gitignore || echo " MISSING from .gitignore: $entry" done fi ```
## OWASP Top 10 代码模式
### 1. 注入(SQL、命令、LDAP)
```bash # SQL injection: string concatenation in queries grep -rn "query\|execute\|cursor" --include='*.{py,js,ts,go,java,rb}' . | \ grep -i "f\"\|format(\|%s\|\${\|+ \"\|concat\|sprintf" | \ grep -iv "parameterized\|placeholder\|prepared"
# Command injection: user input in shell commands grep -rn "exec(\|spawn(\|system(\|popen(\|subprocess\|os\.system\|child_process" \ --include='*.{py,js,ts,go,java,rb}' .
# Check for parameterized queries (good) grep -rn "\\$[0-9]\|\\?\|%s\|:param\|@param\|prepared" --include='*.{py,js,ts,go,java,rb}' . ```
### 2. 失效的身份认证
```bash # Weak password hashing (MD5, SHA1 used for passwords) grep -rn "md5\|sha1\|sha256" --include='*.{py,js,ts,go,java,rb}' . | grep -i "password\|passwd"
# Hardcoded credentials grep -rn -i "admin.*password\|password.*admin\|default.*password" \ --include='*.{py,js,ts,go,java,rb,yml,yaml,json}' .
# Session tokens in URLs grep -rn "session\|token\|jwt" --include='*.{py,js,ts,go,java,rb}' . | grep -i "url\|query\|param\|GET"
# Check for rate limiting on auth endpoints grep -rn -i "rate.limit\|throttle\|brute" --include='*.{py,js,ts,go,java,rb}' . ```
### 3. 跨站脚本攻击(XSS)
```bash # Unescaped output in templates grep -rn "innerHTML\|dangerouslySetInnerHTML\|v-html\|\|html(" \ --include='*.{js,ts,jsx,tsx,vue,html}' .
# Template injection grep -rn "{{{.*}}}\|<%=\|<%-\|\$\!{" --include='*.{html,ejs,hbs,pug,erb}' .
# Document.write grep -rn "document\.write\|document\.writeln" --include='*.{js,ts,html}' .
# eval with user input grep -rn "eval(\|new Function(\|setTimeout.*string\|setInterval.*string" \ --include='*.{js,ts}' . ```
### 4. 不安全的直接对象引用
```bash # Direct ID usage in routes without authz check grep -rn "params\.id\|params\[.id.\]\|req\.params\.\|request\.args\.\|request\.GET\." \ --include='*.{py,js,ts,go,java,rb}' . | \ grep -i "user\|account\|profile\|order\|document" ```
### 5. 安全配置错误
```bash # CORS wildcard grep -rn "Access-Control-Allow-Origin.*\*\|cors({.*origin.*true\|cors()" \ --include='*.{py,js,ts,go,java,rb}' .
# Debug mode in production configs grep -rn "DEBUG\s*=\s*True\|debug:\s*true\|NODE_ENV.*development" \ --include='*.{py,js,ts,yml,yaml,json,env}' .
# Verbose error messages exposed to clients grep -rn "stack\|traceback\|stackTrace" --include='*.{py,js,ts,go,java,rb}' . | \ grep -i "response\|send\|return\|res\." ```
## SSL/TLS 验证
### 检查端点 SSL
```bash # Full SSL check openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | \ openssl x509 -noout -subject -issuer -dates -fingerprint
# Check certificate expiry echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \ openssl x509 -noout -enddate
# Check supported TLS versions for v in tls1 tls1_1 tls1_2 tls1_3; do result=$(openssl s_client -connect example.com:443 -$v < /dev/null 2>&1) if echo "$result" | grep -q "Cipher is"; then echo "$v: SUPPORTED" else echo "$v: NOT SUPPORTED" fi done
# Check cipher suites openssl s_client -connect example.com:443 -cipher 'ALL' < /dev/null 2>&1 | \ grep "Cipher :"
# Check for weak ciphers openssl s_client -connect example.com:443 -cipher 'NULL:EXPORT:DES:RC4:MD5' < /dev/null 2>&1 | \ grep "Cipher :" ```
### 验证证书链
```bash # Download and verify full chain openssl s_client -connect example.com:443 -showcerts < /dev/null 2>/dev/null | \ awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{print}' > chain.pem
# Verify chain openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt chain.pem
# Check certificate details openssl x509 -in chain.pem -noout -text | grep -A2 "Subject:\|Issuer:\|Not Before\|Not After\|DNS:" ```
### 从代码检查 SSL
```bash # Verify SSL isn't disabled in code grep -rn "verify\s*=\s*False\|rejectUnauthorized.*false\|InsecureSkipVerify.*true\|CURLOPT_SSL_VERIFYPEER.*false\|NODE_TLS_REJECT_UNAUTHORIZED.*0" \ --include='*.{py,js,ts,go,java,rb,yml,yaml}' . ```
## 文件权限审计
```bash # Find world-writable files find . -type f -perm -o=w -not -path '*/node_modules/*' -not -path '*/.git/*' 2>/dev/null
# Find executable files that shouldn't be find . -type f -perm -u=x -not -name '*.sh' -not -name '*.py' -not -path '*/node_modules/*' \ -not -path '*/.git/*' -not -path '*/bin/*' 2>/dev/null
# Check sensitive file permissions for f in .env .env.* *.pem *.key *.p12 id_rsa id_ed25519; do [ -f "$f" ] && ls -la "$f" done
# Find files with SUID/SGID bits (Linux) find / -type f \( -perm -4000 -o -perm -2000 \) 2>/dev/null | head -20
# Check SSH key permissions if [ -d ~/.ssh ]; then echo "--- SSH directory permissions ---" ls -la ~/.ssh/ echo "" # Should be: dir=700, private keys=600, public keys=644, config=600 [ "$(stat -c %a ~/.ssh 2>/dev/null || stat -f %Lp ~/.ssh)" != "700" ] && echo "WARNING: ~/.ssh should be 700" fi ```
## 完整项目安全审计脚本
```bash #!/bin/bash # security-audit.sh - Run a comprehensive security check on a project set -euo pipefail
PROJECT_DIR="${1:-.}" cd "$PROJECT_DIR"
echo "=========================================" echo "Security Audit: $(basename "$(pwd)")" echo "Date: $(date -u '+%Y-%m-%dT%H:%M:%SZ')" echo "=========================================" echo ""
ISSUES=0 warn() { echo " [!] $1"; ((ISSUES++)); } ok() { echo " [OK] $1"; } section() { echo ""; echo "--- $1 ---"; }
# 1. Secrets detection section "Secret Detection" for pattern in 'AKIA[0-9A-Z]\{16\}' 'BEGIN.*PRIVATE KEY' 'sk-[A-Za-z0-9]\{20,\}' \ 'ghp_[A-Za-z0-9]\{36\}' 'xox[bpoas]-'; do count=$(grep -rn "$pattern" --include='*.{js,ts,py,go,java,rb,env,yml,yaml,json,xml}' . 2>/dev/null | \ grep -v 'node_modules\|\.git\|vendor\|__pycache__' | wc -l) if [ "$count" -gt 0 ]; then warn "Found $count matches for pattern: $pattern" fi done grep -rn -i 'password\s*[:=]\s*["'"'"'][^"'"'"']*["'"'"']' \ --include='*.{js,ts,py,go,yml,yaml,json,env}' . 2>/dev/null | \ grep -v 'node_modules\|\.git\|example\|test\|mock\|placeholder\|changeme\|xxxx' | \ while read -r line; do warn "Hardcoded password: $line"; done
# 2. Dependency audit section "Dependency Vulnerabilities" if [ -f package-lock.json ] || [ -f package.json ]; then npm audit --audit-level=high 2>/dev/null && ok "npm: no high/critical vulns" || warn "npm audit found issues" fi if [ -f requirements.txt ]; then pip-audit -r requirements.txt 2>/dev/null && ok "pip: no known vulns" || warn "pip-audit found issues" fi if [ -f go.sum ]; then govulncheck ./... 2>/dev/null && ok "Go: no known vulns" || warn "govulncheck found issues" fi
# 3. Gitignore check section ".gitignore Coverage" if [ ! -f .gitignore ]; then warn "No .gitignore file" else for entry in '.env' 'node_modules' '*.key' '*.pem' '.DS_Store'; do grep -q "$entry" .gitignore 2>/dev/null && ok ".gitignore has $entry" || warn ".gitignore missing: $entry" done fi
# 4. SSL verification disabled section "SSL Verification" disabled=$(grep -rn "verify\s*=\s*False\|rejectUnauthorized.*false\|InsecureSkipVerify.*true" \ --include='*.{py,js,ts,go,java,rb}' . 2>/dev/null | \ grep -v 'node_modules\|\.git\|test\|spec\|mock' | wc -l) [ "$disabled" -gt 0 ] && warn "SSL verification disabled in $disabled location(s)" || ok "No SSL bypasses found"
# 5. CORS wildcard section "CORS Configuration" cors=$(grep -rn "Access-Control-Allow-Origin.*\*\|cors({.*origin.*true" \ --include='*.{py,js,ts,go,java,rb}' . 2>/dev/null | \ grep -v 'node_modules\|\.git' | wc -l) [ "$cors" -gt 0 ] && warn "CORS wildcard found in $cors location(s)" || ok "No CORS wildcard"
# 6. Debug mode section "Debug/Development Settings" debug=$(grep -rn "DEBUG\s*=\s*True\|debug:\s*true" \ --include='*.{py,yml,yaml,json}' . 2>/dev/null | \ grep -v 'node_modules\|\.git\|test\|jest\|vitest' | wc -l) [ "$debug" -gt 0 ] && warn "Debug mode enabled in $debug location(s)" || ok "No debug flags found"
echo "" echo "=========================================" echo "Audit complete. Issues found: $ISSUES" echo "=========================================" [ "$ISSUES" -eq 0 ] && exit 0 || exit 1 ```
## 安全编码快速参考
### 使用环境变量代替硬编码密钥
```bash # Bad: hardcoded in source API_KEY="sk-abc123..."
# Good: from environment API_KEY="${API_KEY:?Error: API_KEY not set}"
# Good: from .env file (loaded at startup, never committed) # .env API_KEY=sk-abc123... # .gitignore .env ```
### 输入验证检查清单
``` - [ ] All user input validated (type, length, format) - [ ] SQL queries use parameterized statements (never string concat) - [ ] Shell commands never include user input directly - [ ] File paths validated (no path traversal: ../) - [ ] URLs validated (no SSRF: restrict to expected domains) - [ ] HTML output escaped (no XSS: use framework auto-escaping) - [ ] JSON parsing has error handling (no crash on malformed input) - [ ] File uploads checked (type, size, no executable content) ```
### HTTP 安全头
```bash # Check security headers on a URL curl -sI https://example.com | grep -i 'strict-transport\|content-security\|x-frame\|x-content-type\|referrer-policy\|permissions-policy'
# Expected headers: # Strict-Transport-Security: max-age=31536000; includeSubDomains # Content-Security-Policy: default-src 'self' # X-Frame-Options: DENY # X-Content-Type-Options: nosniff # Referrer-Policy: strict-origin-when-cross-origin # Permissions-Policy: camera=(), microphone=(), geolocation=() ```
## 提示
- 在 CI 的每次拉取请求中运行 `npm audit` / `pip-audit` / `govulncheck`,而不仅仅是偶尔运行。 - Git 历史记录中的密钥检测很重要:即使密钥已从 HEAD 中删除,它仍存在于 git 历史记录中。使用 `git filter-branch` 或 `git-filter-repo` 进行清除,然后轮换该凭证。 - 最危险的漏洞往往是最简单的:通过字符串拼接进行的 SQL 注入、通过未净化输入进行的命令注入、通过 `innerHTML` 进行的 XSS。 - 对于真正公开的只读 API,CORS `Access-Control-Allow-Origin: *` 是安全的。对于使用 Cookie 或身份验证令牌的任何内容,它都是危险的。 - 始终在生产环境中验证 SSL。`verify=False` 或 `rejectUnauthorized: false` 应仅出现在测试代码中,绝不能出现在生产路径中。 - 纵深防御:验证输入、转义输出、使用参数化查询、强制执行最小权限原则,并假设每一层都可能被绕过。