security
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSecurity Skill
安全技能
Version: 1.0
Source: Security Standards
Security must be built in from the start, not bolted on later. These standards apply to all code that handles user data, authentication, or external input.
版本: 1.0
来源: 安全标准
安全必须从一开始就融入设计,而不是事后追加。这些标准适用于所有处理用户数据、身份验证或外部输入的代码。
Core Principles
核心原则
- Security by Design — Build security in from the start, not as an afterthought
- Defense in Depth — Multiple layers of security; no single point of failure
- Least Privilege — Grant minimum access required for the task
- Fail Securely — Errors should not expose vulnerabilities or sensitive data
- Zero Trust — Never trust input, always verify
- Assume Breach — Design as if attackers will get in; minimize blast radius
- 设计安全 — 从一开始就融入安全设计,而非事后补充
- 深度防御 — 多层安全防护,无单点故障
- 最小权限 — 仅授予完成任务所需的最低权限
- 安全失败 — 错误不应暴露漏洞或敏感数据
- 零信任 — 绝不信任任何输入,始终进行验证
- 假设已被攻破 — 按照攻击者已入侵的场景进行设计,最小化影响范围
OWASP Top 10 (2021)
OWASP Top 10(2021版)
Critical vulnerabilities to prevent:
| # | Vulnerability | Prevention |
|---|---|---|
| 1 | Broken Access Control | Check authorization on every request |
| 2 | Cryptographic Failures | Use strong encryption, never roll your own |
| 3 | Injection | Parameterized queries, input validation |
| 4 | Insecure Design | Threat modeling, secure architecture |
| 5 | Security Misconfiguration | Secure defaults, proper error handling |
| 6 | Vulnerable Components | Keep dependencies updated, audit regularly |
| 7 | Auth Failures | Strong auth, MFA, secure session management |
| 8 | Integrity Failures | Verify code/data integrity, sign releases |
| 9 | Logging Failures | Log security events, protect log data |
| 10 | SSRF | Validate and allowlist server-side URLs |
需防范的关键漏洞:
| 序号 | 漏洞类型 | 防范措施 |
|---|---|---|
| 1 | 访问控制失效 | 对每个请求进行授权检查 |
| 2 | 加密失败 | 使用强加密算法,绝不自行实现加密 |
| 3 | 注入攻击 | 使用参数化查询、输入验证 |
| 4 | 不安全设计 | 威胁建模、安全架构设计 |
| 5 | 安全配置错误 | 使用安全默认配置、正确处理错误 |
| 6 | 易受攻击的组件 | 定期更新依赖、进行审计 |
| 7 | 身份验证失败 | 强身份验证、多因素认证(MFA)、安全会话管理 |
| 8 | 完整性失败 | 验证代码/数据完整性、对发布版本签名 |
| 9 | 日志记录失败 | 记录安全事件、保护日志数据 |
| 10 | SSRF(服务器端请求伪造) | 验证并使用白名单限制服务器端URL |
Input Validation
输入验证
The Golden Rule
黄金法则
Never trust user input. All input is potentially malicious.
绝不信任用户输入。所有输入都可能是恶意的。
Validation Strategy
验证策略
1. Validate → 2. Sanitize → 3. Encode (for output context)1. 验证 → 2. 清理 → 3. 编码(根据输出场景)SQL Injection Prevention
SQL注入防范
python
undefinedpython
undefined❌ NEVER - String concatenation
❌ 绝对不要 - 字符串拼接
query = f"SELECT * FROM users WHERE id = {user_id}"
query = f"SELECT * FROM users WHERE id = {user_id}"
✅ ALWAYS - Parameterized queries
✅ 务必使用 - 参数化查询
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
✅ ALWAYS - ORM with parameters
✅ 务必使用 - 带参数的ORM
User.objects.filter(id=user_id)
undefinedUser.objects.filter(id=user_id)
undefinedXSS Prevention
XSS攻击防范
javascript
// ❌ NEVER - Direct HTML insertion
element.innerHTML = userInput;
document.write(userInput);
// ✅ ALWAYS - Text content (auto-escapes)
element.textContent = userInput;
// ✅ ALWAYS - Template literals with escaping
const escaped = escapeHtml(userInput);javascript
// ❌ 绝对不要 - 直接插入HTML
element.innerHTML = userInput;
document.write(userInput);
// ✅ 务必使用 - 文本内容(自动转义)
element.textContent = userInput;
// ✅ 务必使用 - 带转义的模板字符串
const escaped = escapeHtml(userInput);Command Injection Prevention
命令注入防范
python
undefinedpython
undefined❌ NEVER - Shell execution with user input
❌ 绝对不要 - 使用用户输入执行Shell命令
os.system(f"ls {user_path}")
subprocess.call(f"convert {filename}", shell=True)
os.system(f"ls {user_path}")
subprocess.call(f"convert {filename}", shell=True)
✅ ALWAYS - Argument arrays (no shell)
✅ 务必使用 - 参数数组(不通过Shell)
subprocess.run(["ls", user_path], shell=False)
subprocess.run(["convert", filename], shell=False)
undefinedsubprocess.run(["ls", user_path], shell=False)
subprocess.run(["convert", filename], shell=False)
undefinedInput Validation Patterns
输入验证示例
python
import re
def validate_email(email: str) -> bool:
"""Validate email format."""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return bool(re.match(pattern, email)) and len(email) <= 254
def validate_username(username: str) -> bool:
"""Validate username: alphanumeric, 3-30 chars."""
pattern = r'^[a-zA-Z0-9_]{3,30}$'
return bool(re.match(pattern, username))
def validate_url(url: str, allowed_domains: list[str]) -> bool:
"""Validate URL against allowlist."""
from urllib.parse import urlparse
parsed = urlparse(url)
return (
parsed.scheme in ('http', 'https') and
parsed.netloc in allowed_domains
)python
import re
def validate_email(email: str) -> bool:
"""验证邮箱格式。"""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return bool(re.match(pattern, email)) and len(email) <= 254
def validate_username(username: str) -> bool:
"""验证用户名:仅允许字母数字和下划线,长度3-30位。"""
pattern = r'^[a-zA-Z0-9_]{3,30}$'
return bool(re.match(pattern, username))
def validate_url(url: str, allowed_domains: list[str]) -> bool:
"""根据白名单验证URL。"""
from urllib.parse import urlparse
parsed = urlparse(url)
return (
parsed.scheme in ('http', 'https') and
parsed.netloc in allowed_domains
)Authentication & Authorization
身份验证与授权
Password Requirements
密码要求
| Requirement | Minimum |
|---|---|
| Length | 12 characters |
| Complexity | Not required if length met |
| Common passwords | Block top 10,000 |
| Breached passwords | Check against HaveIBeenPwned |
| 要求 | 最小值 |
|---|---|
| 长度 | 12个字符 |
| 复杂度 | 满足长度要求则无需强制复杂度 |
| 常见密码 | 阻止前10000个最常见密码 |
| 泄露密码 | 对照HaveIBeenPwned数据库检查 |
Password Storage
密码存储
python
undefinedpython
undefined✅ Use bcrypt, Argon2, or scrypt
✅ 使用bcrypt、Argon2或scrypt
import bcrypt
def hash_password(password: str) -> bytes:
"""Hash password with bcrypt."""
salt = bcrypt.gensalt(rounds=12)
return bcrypt.hashpw(password.encode(), salt)
def verify_password(password: str, hashed: bytes) -> bool:
"""Verify password against hash."""
return bcrypt.checkpw(password.encode(), hashed)
**NEVER:**
- Store passwords in plain text
- Use MD5 or SHA1 for passwords
- Roll your own hashingimport bcrypt
def hash_password(password: str) -> bytes:
"""使用bcrypt哈希密码。"""
salt = bcrypt.gensalt(rounds=12)
return bcrypt.hashpw(password.encode(), salt)
def verify_password(password: str, hashed: bytes) -> bool:
"""验证密码与哈希值是否匹配。"""
return bcrypt.checkpw(password.encode(), hashed)
**绝对不要:**
- 明文存储密码
- 使用MD5或SHA1存储密码
- 自行实现哈希算法Session Management
会话管理
python
undefinedpython
undefinedSession security settings
会话安全配置
SESSION_CONFIG = {
"cookie_secure": True, # HTTPS only
"cookie_httponly": True, # No JavaScript access
"cookie_samesite": "Lax", # CSRF protection
"session_lifetime": 3600, # 1 hour max
"regenerate_on_login": True # Prevent session fixation
}
undefinedSESSION_CONFIG = {
"cookie_secure": True, # 仅通过HTTPS传输
"cookie_httponly": True, # 禁止JavaScript访问
"cookie_samesite": "Lax", # CSRF防护
"session_lifetime": 3600, # 最长1小时
"regenerate_on_login": True # 防止会话固定攻击
}
undefinedAuthorization Checks
授权检查
python
undefinedpython
undefined✅ Check authorization on EVERY request
✅ 对每个请求都进行授权检查
def get_document(user, document_id):
document = Document.get(document_id)
# Always verify ownership/access
if document.owner_id != user.id and not user.is_admin:
raise PermissionError("Access denied")
return document
---def get_document(user, document_id):
document = Document.get(document_id)
# 始终验证所有权/访问权限
if document.owner_id != user.id and not user.is_admin:
raise PermissionError("访问被拒绝")
return document
---Data Protection
数据保护
Encryption Requirements
加密要求
| Data Type | At Rest | In Transit |
|---|---|---|
| Passwords | Hashed (bcrypt/Argon2) | TLS 1.2+ |
| PII (name, email, address) | AES-256 | TLS 1.2+ |
| Payment data | AES-256 + PCI DSS | TLS 1.3 |
| Health data | AES-256 + HIPAA | TLS 1.3 |
| Session tokens | N/A | TLS 1.2+ |
| API keys | AES-256 | TLS 1.2+ |
| 数据类型 | 静态数据 | 传输中数据 |
|---|---|---|
| 密码 | 哈希处理(bcrypt/Argon2) | TLS 1.2+ |
| 个人身份信息(姓名、邮箱、地址) | AES-256加密 | TLS 1.2+ |
| 支付数据 | AES-256加密 + PCI DSS合规 | TLS 1.3 |
| 健康数据 | AES-256加密 + HIPAA合规 | TLS 1.3 |
| 会话令牌 | 不适用 | TLS 1.2+ |
| API密钥 | AES-256加密 | TLS 1.2+ |
Sensitive Data Handling
敏感数据处理
python
undefinedpython
undefined✅ Mask sensitive data in logs
✅ 在日志中脱敏敏感数据
def log_user_action(user, action, data):
safe_data = {
"user_id": user.id,
"email": mask_email(user.email), # j***@example.com
"action": action,
# Never log: passwords, tokens, full credit cards
}
logger.info("User action", extra=safe_data)
def mask_email(email: str) -> str:
"""Mask email for logging."""
local, domain = email.split("@")
return f"{local[0]}***@{domain}"
def mask_card(card: str) -> str:
"""Show only last 4 digits."""
return f"--****-{card[-4:]}"
undefineddef log_user_action(user, action, data):
safe_data = {
"user_id": user.id,
"email": mask_email(user.email), # j***@example.com
"action": action,
# 绝对不要记录:密码、令牌、完整信用卡号
}
logger.info("用户操作", extra=safe_data)
def mask_email(email: str) -> str:
"""对邮箱进行脱敏以便记录。"""
local, domain = email.split("@")
return f"{local[0]}***@{domain}"
def mask_card(card: str) -> str:
"""仅显示最后4位数字。"""
return f"--****-{card[-4:]}"
undefinedData Retention
数据保留
- Delete data when no longer needed
- Implement data expiration policies
- Provide user data export/deletion (GDPR)
- Securely wipe deleted data (not just mark deleted)
- 不再需要时删除数据
- 实施数据过期策略
- 提供用户数据导出/删除功能(符合GDPR)
- 安全擦除已删除数据(而非仅标记为删除)
API Security
API安全
Rate Limiting
速率限制
python
undefinedpython
undefinedImplement rate limiting per endpoint
为每个端点实现速率限制
RATE_LIMITS = {
"/api/login": "5/minute", # Prevent brute force
"/api/register": "3/minute", # Prevent spam
"/api/password-reset": "3/hour",
"/api/*": "100/minute", # General limit
}
undefinedRATE_LIMITS = {
"/api/login": "5/minute", # 防止暴力破解
"/api/register": "3/minute", # 防止垃圾注册
"/api/password-reset": "3/hour",
"/api/*": "100/minute", # 通用限制
}
undefinedCORS Configuration
CORS配置
python
undefinedpython
undefined✅ Specific origins only
✅ 仅允许特定源
CORS_CONFIG = {
"origins": [
"https://app.example.com",
"https://admin.example.com",
],
"methods": ["GET", "POST", "PUT", "DELETE"],
"allow_credentials": True,
"max_age": 3600,
}
CORS_CONFIG = {
"origins": [
"https://app.example.com",
"https://admin.example.com",
],
"methods": ["GET", "POST", "PUT", "DELETE"],
"allow_credentials": True,
"max_age": 3600,
}
❌ NEVER in production
❌ 生产环境绝对不要这样配置
CORS_CONFIG = {
"origins": "*", # Allows any origin!
}
undefinedCORS_CONFIG = {
"origins": "*", # 允许任何源!
}
undefinedAPI Response Security
API响应安全
python
undefinedpython
undefined❌ Never expose internal errors
❌ 绝对不要暴露内部错误
def handle_error(error):
# Don't send: stack traces, SQL errors, file paths
return {"error": "An error occurred"}, 500
def handle_error(error):
# 不要返回:堆栈跟踪、SQL错误、文件路径
return {"error": "发生错误"}, 500
✅ Log details, return generic message
✅ 记录详细信息,返回通用提示
def handle_error(error):
logger.error(f"Internal error: {error}", exc_info=True)
return {"error": "Internal server error"}, 500
undefineddef handle_error(error):
logger.error(f"内部错误:{error}", exc_info=True)
return {"error": "内部服务器错误"}, 500
undefinedSecurity Headers
安全头
python
SECURITY_HEADERS = {
"Strict-Transport-Security": "max-age=31536000; includeSubDomains",
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"X-XSS-Protection": "1; mode=block",
"Content-Security-Policy": "default-src 'self'",
"Referrer-Policy": "strict-origin-when-cross-origin",
}python
SECURITY_HEADERS = {
"Strict-Transport-Security": "max-age=31536000; includeSubDomains",
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"X-XSS-Protection": "1; mode=block",
"Content-Security-Policy": "default-src 'self'",
"Referrer-Policy": "strict-origin-when-cross-origin",
}Secrets Management
密钥管理
Environment Variables
环境变量
bash
undefinedbash
undefined✅ Store secrets in environment
✅ 将密钥存储在环境变量中
export DATABASE_URL="postgres://..."
export API_KEY="..."
export JWT_SECRET="..."
export DATABASE_URL="postgres://..."
export API_KEY="..."
export JWT_SECRET="..."
❌ NEVER commit secrets to code
❌ 绝对不要将密钥提交到代码中
DATABASE_URL = "postgres://user:password@host/db" # In code!
undefinedDATABASE_URL = "postgres://user:password@host/db" # 写在代码里!
undefinedSecret Requirements
密钥要求
| Secret Type | Rotation Period | Storage |
|---|---|---|
| API keys | 90 days | Vault/env vars |
| Database passwords | 90 days | Vault/env vars |
| JWT secrets | 30 days | Vault/env vars |
| Encryption keys | 1 year | HSM/KMS |
| User passwords | On compromise | Hashed in DB |
| 密钥类型 | 轮换周期 | 存储方式 |
|---|---|---|
| API密钥 | 90天 | 密钥管理系统/环境变量 |
| 数据库密码 | 90天 | 密钥管理系统/环境变量 |
| JWT密钥 | 30天 | 密钥管理系统/环境变量 |
| 加密密钥 | 1年 | 硬件安全模块/密钥管理服务 |
| 用户密码 | 泄露时轮换 | 数据库中哈希存储 |
.gitignore
.gitignore
gitignore
undefinedgitignore
undefinedSecrets - NEVER commit
密钥 - 绝对不要提交
.env
.env.local
.env.*.local
*.pem
.key
credentials.json
secrets.yaml
config/secrets/
---.env
.env.local
.env.*.local
*.pem
.key
credentials.json
secrets.yaml
config/secrets/
---File Upload Security
文件上传安全
Validation Checklist
验证清单
python
def validate_upload(file) -> bool:
"""Validate uploaded file."""
# 1. Check file size
MAX_SIZE = 10 * 1024 * 1024 # 10MB
if file.size > MAX_SIZE:
raise ValueError("File too large")
# 2. Check extension against allowlist
ALLOWED_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.pdf'}
ext = Path(file.name).suffix.lower()
if ext not in ALLOWED_EXTENSIONS:
raise ValueError("File type not allowed")
# 3. Verify magic bytes (don't trust extension)
magic_bytes = file.read(8)
file.seek(0)
if not is_valid_magic(magic_bytes, ext):
raise ValueError("File content doesn't match extension")
# 4. Generate safe filename
safe_name = generate_safe_filename(file.name)
# 5. Store outside web root
storage_path = UPLOAD_DIR / safe_name # Not in /public!
return Truepython
def validate_upload(file) -> bool:
"""验证上传的文件。"""
# 1. 检查文件大小
MAX_SIZE = 10 * 1024 * 1024 # 10MB
if file.size > MAX_SIZE:
raise ValueError("文件过大")
# 2. 检查扩展名是否在白名单中
ALLOWED_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.pdf'}
ext = Path(file.name).suffix.lower()
if ext not in ALLOWED_EXTENSIONS:
raise ValueError("不允许的文件类型")
# 3. 验证魔术字节(不要信任扩展名)
magic_bytes = file.read(8)
file.seek(0)
if not is_valid_magic(magic_bytes, ext):
raise ValueError("文件内容与扩展名不匹配")
# 4. 生成安全文件名
safe_name = generate_safe_filename(file.name)
# 5. 存储在Web根目录之外
storage_path = UPLOAD_DIR / safe_name # 不要放在/public目录下!
return TrueSafe Filename Generation
安全文件名生成
python
import uuid
import re
from pathlib import Path
def generate_safe_filename(original: str) -> str:
"""Generate safe filename, preserving extension."""
ext = Path(original).suffix.lower()
# Use UUID, not original filename
return f"{uuid.uuid4()}{ext}"python
import uuid
import re
from pathlib import Path
def generate_safe_filename(original: str) -> str:
"""生成安全文件名,保留扩展名。"""
ext = Path(original).suffix.lower()
# 使用UUID,而非原始文件名
return f"{uuid.uuid4()}{ext}"Logging & Monitoring
日志与监控
What to Log
需要记录的内容
python
undefinedpython
undefined✅ Log these security events
✅ 记录以下安全事件
SECURITY_EVENTS = [
"login_success",
"login_failure",
"logout",
"password_change",
"password_reset_request",
"permission_denied",
"invalid_token",
"rate_limit_exceeded",
"suspicious_input",
"admin_action",
]
undefinedSECURITY_EVENTS = [
"login_success",
"login_failure",
"logout",
"password_change",
"password_reset_request",
"permission_denied",
"invalid_token",
"rate_limit_exceeded",
"suspicious_input",
"admin_action",
]
undefinedWhat NOT to Log
绝对不要记录的内容
python
undefinedpython
undefined❌ NEVER log these
❌ 绝对不要记录这些内容
NEVER_LOG = [
"password",
"password_hash",
"credit_card",
"ssn",
"api_key",
"session_token",
"jwt_token",
"private_key",
]
undefinedNEVER_LOG = [
"password",
"password_hash",
"credit_card",
"ssn",
"api_key",
"session_token",
"jwt_token",
"private_key",
]
undefinedStructured Security Logging
结构化安全日志
python
def log_security_event(event_type: str, user_id: str, details: dict):
"""Log security event with context."""
logger.info("security_event", extra={
"event_type": event_type,
"user_id": user_id,
"timestamp": datetime.utcnow().isoformat(),
"ip_address": get_client_ip(),
"user_agent": get_user_agent(),
**sanitize_details(details),
})python
def log_security_event(event_type: str, user_id: str, details: dict):
"""记录带上下文的安全事件。"""
logger.info("security_event", extra={
"event_type": event_type,
"user_id": user_id,
"timestamp": datetime.utcnow().isoformat(),
"ip_address": get_client_ip(),
"user_agent": get_user_agent(),
**sanitize_details(details),
})Security Checklist
安全检查清单
Before Every Release
每次发布前检查
- No secrets in code or version control
- All user input validated and sanitized
- SQL queries use parameterized statements
- Authentication on all protected endpoints
- Authorization checks on all resources
- HTTPS enforced (no HTTP)
- Security headers configured
- Rate limiting in place
- Error messages don't leak sensitive info
- Dependencies updated and audited
- File uploads validated and stored safely
- Logging captures security events
- CORS configured restrictively
- 代码或版本控制中无密钥
- 所有用户输入均已验证和清理
- SQL查询使用参数化语句
- 所有受保护端点均有身份验证
- 所有资源均有授权检查
- 强制使用HTTPS(禁止HTTP)
- 已配置安全头
- 已启用速率限制
- 错误信息未泄露敏感信息
- 依赖已更新并审计
- 文件上传已验证并安全存储
- 日志已捕获安全事件
- CORS配置严格
Code Review Security Focus
代码评审安全重点
- Input validation at all entry points
- Output encoding for XSS prevention
- Access control checks present
- No hardcoded secrets
- Proper error handling (no stack traces)
- Secure defaults used
- Third-party libraries are necessary and trusted
- 所有入口点均有输入验证
- 输出编码以防范XSS攻击
- 存在访问控制检查
- 无硬编码密钥
- 正确处理错误(无堆栈跟踪)
- 使用安全默认配置
- 第三方库必要且可信
References
参考资料
- — Detailed OWASP vulnerability guide
references/owasp-top-10.md - — Complete input validation patterns
references/input-validation.md - — Authentication and authorization patterns
references/auth-patterns.md
- — OWASP漏洞详细指南
references/owasp-top-10.md - — 完整输入验证模式
references/input-validation.md - — 身份验证与授权模式
references/auth-patterns.md
Assets
资源
- — Pre-release security checklist
assets/security-checklist.md - — Threat modeling template
assets/threat-model-template.md
- — 发布前安全检查清单
assets/security-checklist.md - — 威胁建模模板
assets/threat-model-template.md
Scripts
脚本
- — Scan code for accidentally committed secrets
scripts/scan_secrets.py - — Check dependencies for known vulnerabilities
scripts/check_dependencies.py
- — 扫描代码中意外提交的密钥
scripts/scan_secrets.py - — 检查依赖项的已知漏洞
scripts/check_dependencies.py