security-hardening

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Security Hardening

安全加固

Input Validation

输入校验

Validate all input at the boundary. Never trust client-side validation alone.
typescript
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(13).max(150),
});

function createUser(req: Request) {
  const result = CreateUserSchema.safeParse(req.body);
  if (!result.success) {
    return { status: 400, errors: result.error.flatten().fieldErrors };
  }
  // result.data is typed and validated
}
Rules:
  • Validate type, length, format, and range on every input
  • Use allowlists over denylists (accept known good, reject everything else)
  • Validate file uploads: check MIME type, file extension, and magic bytes
  • Limit request body size at the server/proxy level (e.g., 1MB max)
在边界层校验所有输入,永远不要只依赖客户端校验。
typescript
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(13).max(150),
});

function createUser(req: Request) {
  const result = CreateUserSchema.safeParse(req.body);
  if (!result.success) {
    return { status: 400, errors: result.error.flatten().fieldErrors };
  }
  // result.data is typed and validated
}
规则:
  • 对所有输入的类型、长度、格式和范围进行校验
  • 优先使用允许列表而非拒绝列表(接受已知合法内容,拒绝其余所有内容)
  • 校验文件上传:检查MIME类型、文件扩展名和魔数
  • 在服务端/代理层限制请求体大小(例如最大1MB)

Output Encoding

输出编码

typescript
// Prevent XSS: encode output based on context
// HTML context: use framework auto-escaping (React does this by default)
// Never use dangerouslySetInnerHTML with user input

// URL context: encode parameters
const safeUrl = `/search?q=${encodeURIComponent(userInput)}`;

// JSON context: use JSON.stringify (handles escaping)
const safeJson = JSON.stringify({ query: userInput });
Never construct HTML strings with user input. Use templating engines with auto-escaping enabled.
typescript
// Prevent XSS: encode output based on context
// HTML context: use framework auto-escaping (React does this by default)
// Never use dangerouslySetInnerHTML with user input

// URL context: encode parameters
const safeUrl = `/search?q=${encodeURIComponent(userInput)}`;

// JSON context: use JSON.stringify (handles escaping)
const safeJson = JSON.stringify({ query: userInput });
永远不要使用用户输入拼接HTML字符串,使用开启了自动转义的模板引擎。

SQL Injection Prevention

SQL注入防护

python
undefined
python
undefined

NEVER do this

NEVER do this

cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")

Always use parameterized queries

Always use parameterized queries

cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))

```typescript
// NEVER do this
db.query(`SELECT * FROM users WHERE email = '${email}'`);

// Always use parameterized queries
db.query("SELECT * FROM users WHERE email = $1", [email]);
Use an ORM or query builder. If writing raw SQL, always parameterize.
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))

```typescript
// NEVER do this
db.query(`SELECT * FROM users WHERE email = '${email}'`);

// Always use parameterized queries
db.query("SELECT * FROM users WHERE email = $1", [email]);
使用ORM或者查询构建器。如果需要编写原生SQL,必须使用参数化查询。

CSRF Protection

CSRF防护

typescript
// Server: generate and validate CSRF tokens
import { randomBytes } from 'crypto';

function generateCsrfToken(): string {
  return randomBytes(32).toString('hex');
}

// Middleware: validate on state-changing requests
function csrfMiddleware(req, res, next) {
  if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {
    const token = req.headers['x-csrf-token'] || req.body._csrf;
    if (!timingSafeEqual(token, req.session.csrfToken)) {
      return res.status(403).json({ error: 'Invalid CSRF token' });
    }
  }
  next();
}
For APIs with token-based auth (Bearer tokens), CSRF is not needed since the token is not auto-sent by browsers.
typescript
// Server: generate and validate CSRF tokens
import { randomBytes } from 'crypto';

function generateCsrfToken(): string {
  return randomBytes(32).toString('hex');
}

// Middleware: validate on state-changing requests
function csrfMiddleware(req, res, next) {
  if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {
    const token = req.headers['x-csrf-token'] || req.body._csrf;
    if (!timingSafeEqual(token, req.session.csrfToken)) {
      return res.status(403).json({ error: 'Invalid CSRF token' });
    }
  }
  next();
}
对于使用基于令牌的身份验证(Bearer tokens)的API,不需要CSRF防护,因为浏览器不会自动发送这类令牌。

Content Security Policy

内容安全策略

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-{random}';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  font-src 'self';
  connect-src 'self' https://api.example.com;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';
Start strict, relax as needed. Use
nonce
for inline scripts instead of
unsafe-inline
. Report violations with
report-uri
directive. Test with
Content-Security-Policy-Report-Only
first.
Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-{random}';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  font-src 'self';
  connect-src 'self' https://api.example.com;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';
初始配置从严格模式开始,再按需放宽限制。对 inline 脚本使用
nonce
而非
unsafe-inline
。使用
report-uri
指令上报违规情况。先使用
Content-Security-Policy-Report-Only
模式进行测试。

Security Headers

安全请求头

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Set these on every response. Use
helmet
(Node.js) or equivalent middleware.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
对所有响应设置上述请求头,使用
helmet
(Node.js)或对等中间件实现配置。

Rate Limiting

限流

typescript
// Per-user, per-endpoint rate limiting
const rateLimits = {
  'POST /auth/login':    { window: '15m', max: 5 },
  'POST /auth/register': { window: '1h',  max: 3 },
  'POST /api/*':         { window: '1m',  max: 60 },
  'GET /api/*':          { window: '1m',  max: 120 },
};
Use sliding window algorithm. Store counters in Redis. Return
429
with
Retry-After
header. Apply stricter limits to authentication endpoints.
typescript
// Per-user, per-endpoint rate limiting
const rateLimits = {
  'POST /auth/login':    { window: '15m', max: 5 },
  'POST /auth/register': { window: '1h',  max: 3 },
  'POST /api/*':         { window: '1m',  max: 60 },
  'GET /api/*':          { window: '1m',  max: 120 },
};
使用滑动窗口算法,在Redis中存储计数器。返回
429
状态码和
Retry-After
请求头。对身份验证相关接口应用更严格的限流规则。

JWT Best Practices

JWT最佳实践

  • Use short expiry (15 minutes) for access tokens
  • Use refresh tokens (7-30 days) stored in httpOnly cookies
  • Sign with RS256 (asymmetric) for microservices, HS256 (symmetric) for monoliths
  • Never store sensitive data in JWT payload (it is base64 encoded, not encrypted)
  • Validate
    iss
    ,
    aud
    ,
    exp
    , and
    nbf
    claims on every request
  • Implement token revocation via a denylist or short expiry + rotation
typescript
// Verify JWT with all checks
const payload = jwt.verify(token, publicKey, {
  algorithms: ['RS256'],
  issuer: 'auth.example.com',
  audience: 'api.example.com',
  clockTolerance: 30,
});
  • 访问令牌使用短有效期(15分钟)
  • 刷新令牌有效期设置为7-30天,存储在httpOnly cookie中
  • 微服务场景使用RS256(非对称加密)签名,单体应用使用HS256(对称加密)签名
  • 永远不要在JWT payload中存储敏感数据(payload仅做base64编码,未加密)
  • 每次请求都校验
    iss
    aud
    exp
    nbf
    声明
  • 通过拒绝列表或短有效期+令牌轮换实现令牌撤销
typescript
// Verify JWT with all checks
const payload = jwt.verify(token, publicKey, {
  algorithms: ['RS256'],
  issuer: 'auth.example.com',
  audience: 'api.example.com',
  clockTolerance: 30,
});

Secrets Management

密钥管理

  • Never commit secrets to version control (use
    .gitignore
    for
    .env
    )
  • Use environment variables for runtime secrets
  • Use a secrets manager in production (AWS Secrets Manager, HashiCorp Vault, Doppler)
  • Rotate secrets regularly (90-day maximum for API keys)
  • Use different secrets per environment (dev/staging/prod)
  • Scan for leaked secrets in CI:
    trufflehog
    ,
    gitleaks
    ,
    git-secrets
bash
undefined
  • 永远不要将密钥提交到版本控制系统(使用
    .gitignore
    忽略
    .env
    文件)
  • 运行时密钥使用环境变量存储
  • 生产环境使用密钥管理服务(AWS Secrets Manager、HashiCorp Vault、Doppler)
  • 定期轮换密钥(API密钥最长有效期为90天)
  • 不同环境使用不同密钥(开发/预发布/生产)
  • 在CI中扫描泄露的密钥:
    trufflehog
    gitleaks
    git-secrets
bash
undefined

Check for secrets in git history

Check for secrets in git history

gitleaks detect --source . --verbose
gitleaks detect --source . --verbose

Pre-commit hook to prevent secret commits

Pre-commit hook to prevent secret commits

gitleaks protect --staged
undefined
gitleaks protect --staged
undefined

Dependency Auditing

依赖审计

bash
undefined
bash
undefined

Node.js

Node.js

npm audit --production npx better-npm-audit audit --level=high
npm audit --production npx better-npm-audit audit --level=high

Python

Python

pip-audit safety check
pip-audit safety check

Go

Go

govulncheck ./...

Run dependency audits in CI on every PR. Block merges on critical/high vulnerabilities. Pin dependency versions. Update dependencies weekly with automated PRs (Dependabot, Renovate).
govulncheck ./...

每次PR提交时在CI中运行依赖审计,存在严重/高危漏洞时阻止合并。固定依赖版本,通过自动PR(Dependabot、Renovate)每周更新依赖。

Checklist Before Deploy

部署前检查清单

  1. All inputs validated with schema validation
  2. SQL queries parameterized
  3. Security headers configured
  4. HTTPS enforced with HSTS
  5. Secrets externalized, not in code
  6. Dependencies audited, no critical vulnerabilities
  7. Rate limiting on all public endpoints
  8. Authentication tokens expire and rotate
  9. Error messages do not leak internal details
  10. Logging captures security events without sensitive data
  1. 所有输入都通过了schema校验
  2. SQL查询都使用了参数化
  3. 安全请求头已配置
  4. 通过HSTS强制使用HTTPS
  5. 密钥已外置,不存在于代码中
  6. 依赖已完成审计,无严重漏洞
  7. 所有公开接口都配置了限流
  8. 身份验证令牌支持过期和轮换
  9. 错误信息不会泄露内部细节
  10. 日志记录安全事件且不含敏感数据