security

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Security 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
.gitignore
:
gitignore
undefined
每个项目的
.gitignore
中必须包含以下内容:
gitignore
undefined

Environment 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/
undefined

2. Environment Variables

2. 环境变量

Create
.env.example
with all required vars (no values):
bash
undefined
**创建
.env.example
**文件,包含所有必需的变量(无需填写值):
bash
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=
undefined
VITE_SUPABASE_URL= VITE_SUPABASE_ANON_KEY=
undefined

Frontend Environment Variables (Critical!)

前端环境变量(至关重要!)

NEVER put secrets in client-exposed env vars:
FrameworkClient-Exposed PrefixServer-Only
Vite
VITE_*
No prefix
Next.js
NEXT_PUBLIC_*
No prefix
Create React App
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
    VITE_
    prefix are server-only
  • Only
    VITE_*
    vars are bundled into client code
  • 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
VITE_*
无前缀
Next.js
NEXT_PUBLIC_*
无前缀
Create React App
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
undefined

config/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

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
undefined
repos:

Detect secrets

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
undefined

Add 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
undefined
safety check # Check dependencies for vulnerabilities bandit -r src/ # Static security analysis
undefined

Security Check Script

安全检查脚本

Create
scripts/security-check.sh
:
bash
#!/bin/bash
set -e

echo "Running security checks..."
创建
scripts/security-check.sh
bash
#!/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.sh

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.sh

GitHub Actions Security Workflow

GitHub Actions安全工作流

Create
.github/workflows/security.yml
:
yaml
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.yml
yaml
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

Input 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
undefined

BAD - 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()
undefined
user = session.query(User).filter(User.id == user_id).first()
undefined

2. 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
undefined

Security 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_*
    ,
    NEXT_PUBLIC_*
    , or
    REACT_APP_*
    env vars (client-exposed!)
  • ❌ Secrets in code or config files committed to git
  • ❌ .env files without .gitignore entry
  • ❌ String concatenation for SQL queries
  • dangerouslySetInnerHTML
    without sanitization
  • eval()
    or
    new Function()
    with user input
  • ❌ 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验证