security
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSecurity Skill
安全技能
Load with: base.md
Security best practices and automated security testing for all projects.
加载自: base.md
适用于所有项目的安全最佳实践与自动化安全测试。
Core Principle
核心原则
Security is not optional. Every project must pass security checks before merge. Assume all input is malicious, all secrets will leak if committed, and all dependencies have vulnerabilities.
安全并非可选项。 所有项目在合并前必须通过安全检查。假设所有输入都是恶意的,所有密钥如果提交都会泄露,所有依赖都存在漏洞。
Required Security Setup
必需的安全设置
1. Gitignore (Non-Negotiable)
1. Gitignore(强制执行)
Every project must have these in :
.gitignoregitignore
undefined每个项目的中必须包含以下内容:
.gitignoregitignore
undefinedEnvironment files - NEVER commit
Environment files - NEVER commit
.env
.env.*
!.env.example
.env
.env.*
!.env.example
Secrets
Secrets
*.pem
*.key
*.p12
*.pfx
credentials.json
secrets.json
-credentials.json
service-account.json
*.pem
*.key
*.p12
*.pfx
credentials.json
secrets.json
-credentials.json
service-account.json
IDE and OS
IDE and OS
.idea/
.vscode/settings.json
.DS_Store
Thumbs.db
.idea/
.vscode/settings.json
.DS_Store
Thumbs.db
Dependencies
Dependencies
node_modules/
pycache/
*.pyc
.venv/
venv/
node_modules/
pycache/
*.pyc
.venv/
venv/
Build outputs
Build outputs
dist/
build/
*.egg-info/
dist/
build/
*.egg-info/
Logs that might contain sensitive data
Logs that might contain sensitive data
*.log
logs/
undefined*.log
logs/
undefined2. Environment Variables
2. 环境变量
Create with all required vars (no values):
.env.examplebash
undefined**创建**文件,包含所有必需的变量(无需填写值):
.env.examplebash
undefined.env.example - Copy to .env and fill in values
.env.example - Copy to .env and fill in values
Server-side only (NEVER prefix with VITE_ or NEXT_PUBLIC_)
Server-side only (NEVER prefix with VITE_ or NEXT_PUBLIC_)
DATABASE_URL=
ANTHROPIC_API_KEY=
SUPABASE_SERVICE_ROLE_KEY=
DATABASE_URL=
ANTHROPIC_API_KEY=
SUPABASE_SERVICE_ROLE_KEY=
Client-side safe (public, non-sensitive)
Client-side safe (public, non-sensitive)
VITE_SUPABASE_URL=
VITE_SUPABASE_ANON_KEY=
undefinedVITE_SUPABASE_URL=
VITE_SUPABASE_ANON_KEY=
undefinedFrontend Environment Variables (Critical!)
前端环境变量(至关重要!)
NEVER put secrets in client-exposed env vars:
| Framework | Client-Exposed Prefix | Server-Only |
|---|---|---|
| Vite | | No prefix |
| Next.js | | No prefix |
| Create React App | | N/A (no server) |
typescript
// WRONG - Secret exposed to browser bundle!
const apiKey = import.meta.env.VITE_ANTHROPIC_API_KEY;
// CORRECT - Only public values client-side
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
// CORRECT - Secrets stay server-side only
// In API route or server function:
const apiKey = process.env.ANTHROPIC_API_KEY;Vercel Environment Variables:
- In Vercel dashboard, secrets without prefix are server-only
VITE_ - Only vars are bundled into client code
VITE_* - Always verify in browser devtools → Sources → your bundle that secrets aren't exposed
Validate environment at startup:
typescript
// config/env.ts
import { z } from 'zod';
const envSchema = z.object({
DATABASE_URL: z.string().url(),
ANTHROPIC_API_KEY: z.string().min(1),
NODE_ENV: z.enum(['development', 'production', 'test']),
});
export const env = envSchema.parse(process.env);python
undefined绝不要将密钥放在客户端可访问的环境变量中:
| 框架 | 客户端暴露前缀 | 仅服务端可用 |
|---|---|---|
| Vite | | 无前缀 |
| Next.js | | 无前缀 |
| Create React App | | 不适用(无服务端) |
typescript
// 错误示例 - 密钥暴露在浏览器包中!
const apiKey = import.meta.env.VITE_ANTHROPIC_API_KEY;
// 正确示例 - 客户端仅使用公开值
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
// 正确示例 - 密钥仅保留在服务端
// 在API路由或服务端函数中:
const apiKey = process.env.ANTHROPIC_API_KEY;Vercel环境变量:
- 在Vercel控制台中,不带前缀的密钥仅服务端可用
VITE_ - 只有变量会被打包到客户端代码中
VITE_* - 务必在浏览器开发者工具 → 源代码 → 你的包中验证,确保密钥未被暴露
启动时验证环境变量:
typescript
// config/env.ts
import { z } from 'zod';
const envSchema = z.object({
DATABASE_URL: z.string().url(),
ANTHROPIC_API_KEY: z.string().min(1),
NODE_ENV: z.enum(['development', 'production', 'test']),
});
export const env = envSchema.parse(process.env);python
undefinedconfig/env.py
config/env.py
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
database_url: str
anthropic_api_key: str
environment: str = "development"
class Config:
env_file = ".env"settings = Settings()
---from pydantic_settings import BaseSettings
class Settings(BaseSettings):
database_url: str
anthropic_api_key: str
environment: str = "development"
class Config:
env_file = ".env"settings = Settings()
---Security Tests
安全测试
Pre-Commit Security Checks
提交前安全检查
Add to pre-commit hooks:
For all projects:
yaml
undefined添加到pre-commit钩子:
所有项目通用:
yaml
undefined.pre-commit-config.yaml (add to existing)
.pre-commit-config.yaml (add to existing)
repos:
Detect secrets
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets args: ['--baseline', '.secrets.baseline']
Check for security issues in dependencies
- repo: local
hooks:
- id: security-check name: security-check entry: ./scripts/security-check.sh language: script pass_filenames: false
**TypeScript/JavaScript:**
```json
// package.json scripts
{
"scripts": {
"security:audit": "npm audit --audit-level=high",
"security:secrets": "npx secretlint '**/*'",
"security:deps": "npx better-npm-audit audit"
}
}Python:
bash
undefinedrepos:
Detect secrets
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets args: ['--baseline', '.secrets.baseline']
Check for security issues in dependencies
- repo: local
hooks:
- id: security-check name: security-check entry: ./scripts/security-check.sh language: script pass_filenames: false
**TypeScript/JavaScript项目:**
```json
// package.json scripts
{
"scripts": {
"security:audit": "npm audit --audit-level=high",
"security:secrets": "npx secretlint '**/*'",
"security:deps": "npx better-npm-audit audit"
}
}Python项目:
bash
undefinedAdd to dev dependencies
Add to dev dependencies
pip install safety bandit
pip install safety bandit
Commands
Commands
safety check # Check dependencies for vulnerabilities
bandit -r src/ # Static security analysis
undefinedsafety check # Check dependencies for vulnerabilities
bandit -r src/ # Static security analysis
undefinedSecurity Check Script
安全检查脚本
Create :
scripts/security-check.shbash
#!/bin/bash
set -e
echo "Running security checks..."创建:
scripts/security-check.shbash
#!/bin/bash
set -e
echo "Running security checks..."Check for secrets in staged files
Check for secrets in staged files
echo "Checking for secrets..."
if command -v detect-secrets &> /dev/null; then
detect-secrets scan --baseline .secrets.baseline
fi
echo "Checking for secrets..."
if command -v detect-secrets &> /dev/null; then
detect-secrets scan --baseline .secrets.baseline
fi
Check .env is not staged
Check .env is not staged
if git diff --cached --name-only | grep -E '^.env$|^.env.' | grep -v '.example$'; then
echo "ERROR: .env file is staged for commit!"
exit 1
fi
if git diff --cached --name-only | grep -E '^.env$|^.env.' | grep -v '.example$'; then
echo "ERROR: .env file is staged for commit!"
exit 1
fi
Check for common secret patterns in staged files
Check for common secret patterns in staged files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
if echo "$STAGED_FILES" | xargs grep -l -E '(password|secret|api_key|apikey|token|private_key)\s*[:=]\s*["\047][^"\047]+["\047]' 2>/dev/null; then
echo "ERROR: Possible secrets found in staged files!"
exit 1
fi
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
if echo "$STAGED_FILES" | xargs grep -l -E '(password|secret|api_key|apikey|token|private_key)\s*[:=]\s*["\047][^"\047]+["\047]' 2>/dev/null; then
echo "ERROR: Possible secrets found in staged files!"
exit 1
fi
Language-specific checks
Language-specific checks
if [ -f "package.json" ]; then
echo "Checking npm dependencies..."
npm audit --audit-level=high || echo "Warning: npm audit found issues"
fi
if [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then
echo "Checking Python dependencies..."
if command -v safety &> /dev/null; then
safety check || echo "Warning: safety found issues"
fi
fi
echo "Security checks passed!"
```bash
chmod +x scripts/security-check.shif [ -f "package.json" ]; then
echo "Checking npm dependencies..."
npm audit --audit-level=high || echo "Warning: npm audit found issues"
fi
if [ -f "pyproject.toml" ] || [ -f "requirements.txt" ]; then
echo "Checking Python dependencies..."
if command -v safety &> /dev/null; then
safety check || echo "Warning: safety found issues"
fi
fi
echo "Security checks passed!"
```bash
chmod +x scripts/security-check.shGitHub Actions Security Workflow
GitHub Actions安全工作流
Create :
.github/workflows/security.ymlyaml
name: Security
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
# Run weekly on Monday at 9am UTC
- cron: '0 9 * * 1'
jobs:
secrets-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect secrets
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.pull_request.base.sha }}
head: ${{ github.event.pull_request.head.sha }}
dependency-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Node.js projects
- name: Setup Node
if: hashFiles('package.json') != ''
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
if: hashFiles('package.json') != ''
run: npm ci
- name: NPM Audit
if: hashFiles('package.json') != ''
run: npm audit --audit-level=high
# Python projects
- name: Setup Python
if: hashFiles('pyproject.toml') != '' || hashFiles('requirements.txt') != ''
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install safety
if: hashFiles('pyproject.toml') != '' || hashFiles('requirements.txt') != ''
run: pip install safety
- name: Safety check
if: hashFiles('pyproject.toml') != '' || hashFiles('requirements.txt') != ''
run: safety check
codeql:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ hashFiles('package.json') != '' && 'javascript-typescript' || 'python' }}
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3创建:
.github/workflows/security.ymlyaml
name: Security
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
# Run weekly on Monday at 9am UTC
- cron: '0 9 * * 1'
jobs:
secrets-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect secrets
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.pull_request.base.sha }}
head: ${{ github.event.pull_request.head.sha }}
dependency-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Node.js projects
- name: Setup Node
if: hashFiles('package.json') != ''
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
if: hashFiles('package.json') != ''
run: npm ci
- name: NPM Audit
if: hashFiles('package.json') != ''
run: npm audit --audit-level=high
# Python projects
- name: Setup Python
if: hashFiles('pyproject.toml') != '' || hashFiles('requirements.txt') != ''
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install safety
if: hashFiles('pyproject.toml') != '' || hashFiles('requirements.txt') != ''
run: pip install safety
- name: Safety check
if: hashFiles('pyproject.toml') != '' || hashFiles('requirements.txt') != ''
run: safety check
codeql:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ hashFiles('package.json') != '' && 'javascript-typescript' || 'python' }}
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3Input Validation (OWASP Top 10)
输入验证(OWASP Top 10)
1. SQL Injection Prevention
1. SQL注入防护
Never use string concatenation:
typescript
// BAD - SQL injection vulnerable
const user = await db.query(`SELECT * FROM users WHERE id = ${userId}`);
// GOOD - Parameterized query
const user = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
// GOOD - Using ORM (Kysely, Prisma, Drizzle)
const user = await db.selectFrom('users').where('id', '=', userId).execute();python
undefined绝不要使用字符串拼接:
typescript
// 错误示例 - 易受SQL注入攻击
const user = await db.query(`SELECT * FROM users WHERE id = ${userId}`);
// 正确示例 - 参数化查询
const user = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
// 正确示例 - 使用ORM(Kysely、Prisma、Drizzle)
const user = await db.selectFrom('users').where('id', '=', userId).execute();python
undefinedBAD - SQL injection vulnerable
错误示例 - 易受SQL注入攻击
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
GOOD - Parameterized query
正确示例 - 参数化查询
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
GOOD - Using ORM (SQLAlchemy)
正确示例 - 使用ORM(SQLAlchemy)
user = session.query(User).filter(User.id == user_id).first()
undefineduser = session.query(User).filter(User.id == user_id).first()
undefined2. XSS Prevention
2. XSS防护
typescript
// Always sanitize user input before rendering
import DOMPurify from 'dompurify';
// BAD - XSS vulnerable
element.innerHTML = userInput;
// GOOD - Sanitized
element.innerHTML = DOMPurify.sanitize(userInput);
// BEST - Use framework's built-in escaping (React does this by default)
return <div>{userInput}</div>; // Safe in React
// DANGER - Bypasses React's protection
return <div dangerouslySetInnerHTML={{ __html: userInput }} />; // Avoid!typescript
// 渲染前务必清理用户输入
import DOMPurify from 'dompurify';
// 错误示例 - 易受XSS攻击
element.innerHTML = userInput;
// 正确示例 - 已清理
element.innerHTML = DOMPurify.sanitize(userInput);
// 最佳实践 - 使用框架内置的转义功能(React默认会自动处理)
return <div>{userInput}</div>; // 在React中是安全的
// 危险操作 - 绕过React的保护机制
return <div dangerouslySetInnerHTML={{ __html: userInput }} />; // 请避免!3. Input Validation at Boundaries
3. 边界处的输入验证
typescript
// Validate ALL external input with Zod
import { z } from 'zod';
const CreateUserSchema = z.object({
email: z.string().email().max(255),
name: z.string().min(1).max(100).regex(/^[a-zA-Z\s]+$/),
age: z.number().int().min(0).max(150),
});
// In route handler
app.post('/users', async (req, res) => {
const result = CreateUserSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ error: result.error });
}
// result.data is now typed and validated
});typescript
// 使用Zod验证所有外部输入
import { z } from 'zod';
const CreateUserSchema = z.object({
email: z.string().email().max(255),
name: z.string().min(1).max(100).regex(/^[a-zA-Z\s]+$/),
age: z.number().int().min(0).max(150),
});
// 在路由处理器中
app.post('/users', async (req, res) => {
const result = CreateUserSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ error: result.error });
}
// result.data现在已被类型化并验证通过
});4. Path Traversal Prevention
4. 路径遍历防护
typescript
import path from 'path';
// BAD - Path traversal vulnerable
const filePath = `./uploads/${req.params.filename}`;
// GOOD - Validate and sanitize path
const filename = path.basename(req.params.filename); // Strips ../
const filePath = path.join('./uploads', filename);
// Verify it's still within allowed directory
if (!filePath.startsWith(path.resolve('./uploads'))) {
throw new Error('Invalid path');
}typescript
import path from 'path';
// 错误示例 - 易受路径遍历攻击
const filePath = `./uploads/${req.params.filename}`;
// 正确示例 - 验证并清理路径
const filename = path.basename(req.params.filename); // 移除../
const filePath = path.join('./uploads', filename);
// 验证路径仍在允许的目录内
if (!filePath.startsWith(path.resolve('./uploads'))) {
throw new Error('无效路径');
}Authentication & Authorization
身份认证与授权
JWT Best Practices
JWT最佳实践
typescript
import jwt from 'jsonwebtoken';
// Token generation
function generateToken(userId: string): string {
return jwt.sign(
{ sub: userId },
process.env.JWT_SECRET!,
{
expiresIn: '15m', // Short-lived access tokens
algorithm: 'HS256',
}
);
}
// Token verification
function verifyToken(token: string): { sub: string } {
return jwt.verify(token, process.env.JWT_SECRET!, {
algorithms: ['HS256'], // Explicitly specify allowed algorithms
}) as { sub: string };
}typescript
import jwt from 'jsonwebtoken';
// 生成令牌
function generateToken(userId: string): string {
return jwt.sign(
{ sub: userId },
process.env.JWT_SECRET!,
{
expiresIn: '15m', // 短期访问令牌
algorithm: 'HS256',
}
);
}
// 验证令牌
function verifyToken(token: string): { sub: string } {
return jwt.verify(token, process.env.JWT_SECRET!, {
algorithms: ['HS256'], // 明确指定允许的算法
}) as { sub: string };
}Password Hashing
密码哈希
typescript
import bcrypt from 'bcrypt';
const SALT_ROUNDS = 12; // Minimum 10, recommended 12+
async function hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, SALT_ROUNDS);
}
async function verifyPassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}python
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(password: str, hashed: str) -> bool:
return pwd_context.verify(password, hashed)typescript
import bcrypt from 'bcrypt';
const SALT_ROUNDS = 12; // 最少10轮,推荐12轮及以上
async function hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, SALT_ROUNDS);
}
async function verifyPassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}python
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(password: str, hashed: str) -> bool:
return pwd_context.verify(password, hashed)Rate Limiting
速率限制
typescript
import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
standardHeaders: true,
legacyHeaders: false,
});
// Apply to auth routes
app.use('/api/auth', rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 5, // 5 attempts per minute
message: 'Too many login attempts, please try again later',
}));typescript
import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 每个窗口最多100次请求
standardHeaders: true,
legacyHeaders: false,
});
// 应用到认证路由
app.use('/api/auth', rateLimit({
windowMs: 60 * 1000, // 1分钟
max: 5, // 每分钟最多5次尝试
message: '登录尝试次数过多,请稍后再试',
}));Security Headers
安全头
typescript
import helmet from 'helmet';
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
},
}));typescript
import helmet from 'helmet';
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
},
}));Security Testing Checklist
安全测试检查清单
Run before every release:
markdown
undefined每次发布前执行:
markdown
undefinedSecurity Checklist
安全检查清单
Secrets & Environment
密钥与环境
- No secrets in code (run detect-secrets)
- .env files in .gitignore
- .env.example exists with all required vars
- Environment validated at startup
- 代码中无密钥(运行detect-secrets)
- .env文件已添加到.gitignore
- .env.example已存在,包含所有必需变量
- 启动时已验证环境变量
Dependencies
依赖
- npm audit / safety check passes
- No known vulnerabilities in dependencies
- Dependencies up to date (Dependabot enabled)
- npm audit / safety check通过
- 依赖中无已知漏洞
- 依赖已更新(已启用Dependabot)
Input Validation
输入验证
- All API inputs validated with schema (Zod/Pydantic)
- File uploads restricted by type and size
- Path traversal prevented
- 所有API输入已通过模式验证(Zod/Pydantic)
- 文件上传已限制类型和大小
- 已防止路径遍历
Authentication
身份认证
- Passwords hashed with bcrypt (12+ rounds)
- JWTs use short expiration
- Rate limiting on auth endpoints
- Session tokens rotated on login
- 密码已使用bcrypt哈希(12轮及以上)
- JWT使用短期过期时间
- 认证端点已设置速率限制
- 登录时会话令牌已轮换
Database
数据库
- Parameterized queries only
- Least privilege database user
- Connection strings not logged
- 仅使用参数化查询
- 数据库用户使用最小权限
- 连接字符串未被记录
Headers & CORS
头信息与CORS
- Security headers enabled (helmet)
- CORS restricted to known origins
- HTTPS only in production
- 已启用安全头(helmet)
- CORS已限制为已知来源
- 生产环境仅使用HTTPS
Logging
日志
- No secrets in logs
- No PII in logs (or properly masked)
- Failed auth attempts logged
---- 日志中无密钥
- 日志中无PII(或已正确掩码)
- 失败的认证尝试已被记录
---Security Anti-Patterns
安全反模式
- ❌ Secrets in ,
VITE_*, orNEXT_PUBLIC_*env vars (client-exposed!)REACT_APP_* - ❌ Secrets in code or config files committed to git
- ❌ .env files without .gitignore entry
- ❌ String concatenation for SQL queries
- ❌ without sanitization
dangerouslySetInnerHTML - ❌ or
eval()with user inputnew Function() - ❌ Passwords stored as plain text or weak hash (MD5, SHA1)
- ❌ JWTs with no expiration or very long expiration
- ❌ No rate limiting on authentication endpoints
- ❌ Logging sensitive data (passwords, tokens, PII)
- ❌ Using for CORS origins in production
* - ❌ Ignoring npm audit / safety check warnings
- ❌ Running as root / admin in production
- ❌ Hardcoded credentials for any environment
- ❌ Disabling SSL/TLS verification
- ❌ 将密钥放在、
VITE_*或NEXT_PUBLIC_*环境变量中(会暴露给客户端!)REACT_APP_* - ❌ 将密钥提交到git的代码或配置文件中
- ❌ .env文件未添加到.gitignore
- ❌ 使用字符串拼接构建SQL查询
- ❌ 未清理就使用
dangerouslySetInnerHTML - ❌ 使用或
eval()处理用户输入new Function() - ❌ 密码以明文或弱哈希(MD5、SHA1)存储
- ❌ JWT未设置过期时间或过期时间过长
- ❌ 认证端点未设置速率限制
- ❌ 日志中记录敏感数据(密码、令牌、PII)
- ❌ 生产环境中CORS来源使用
* - ❌ 忽略npm audit / safety check警告
- ❌ 生产环境中以root/管理员身份运行
- ❌ 任何环境中使用硬编码凭证
- ❌ 禁用SSL/TLS验证