mcpskills.net
技能MCP智能体提示词
mcpskills.net — A curated directory of AI agent Skills and MCP servers
TermsPrivacy
← 返回技能
Development

安全与加固

针对漏洞对代码进行加固。在处理用户输入、认证、数据存储或外部集成时使用。

作者:Addy Osmani仓库 →来源 →

面向 Web 应用的安全优先开发实践。把每一个外部输入都当作敌意输入来对待。

使用场景

  • 构建任何接受用户输入的功能
  • 实现认证或授权
  • 存储或传输敏感数据
  • 与外部 API 或服务集成
  • 添加文件上传、Webhook 或回调
  • 处理支付或 PII(个人身份信息)数据

先做威胁建模

在加固之前,花五分钟像攻击者一样思考:

  1. 梳理信任边界。 不可信数据从哪里进入你的系统?
  2. 明确资产。 什么值得被窃取或破坏?
  3. 对每个边界运行 STRIDE 分析:

| 威胁 | 提问 | 典型缓解措施 | |---|---|---| | Spoofing(仿冒) | 是否有人能冒充某个用户/服务? | 认证、签名验证 | | Tampering(篡改) | 数据能否在传输中或静态时被篡改? | 完整性校验、参数化查询 | | Repudiation(抵赖) | 某个操作之后能否被否认? | 对安全事件进行审计日志记录 | | Information disclosure(信息泄露) | 数据是否会泄露? | 加密、字段允许列表 | | Denial of service(拒绝服务) | 是否会被压垮? | 限流、输入大小上限 | | Elevation of privilege(权限提升) | 用户能否获得本不应有的权限? | 授权检查、最小权限原则 |

三层边界系统

始终执行(无例外)

  • 在系统边界验证所有外部输入
  • 参数化所有数据库查询 —— 绝不将用户输入拼接进 SQL
  • 对输出进行编码以防止 XSS
  • 对所有外部通信使用 HTTPS
  • 使用 bcrypt/scrypt/argon2 对密码进行哈希
  • 设置安全响应头(CSP、HSTS、X-Frame-Options)
  • 会话使用 httpOnly、secure、sameSite cookie
  • 在每次发布前运行 npm audit

先询问(需人工批准)

  • 添加新的认证流程
  • 存储新类别的敏感数据
  • 添加新的外部服务集成
  • 修改 CORS 配置
  • 添加文件上传处理器

绝不执行

  • 绝不将密钥提交到版本控制
  • 绝不记录敏感数据(密码、令牌、完整的信用卡号)
  • 绝不将客户端校验当作安全边界来信任
  • 绝不为图方便而禁用安全响应头
  • 绝不对用户提供的数据使用 eval() 或 innerHTML

OWASP Top 10 防护模式

注入(SQL、NoSQL、操作系统命令)

// BAD: SQL injection via string concatenation
const query = `SELECT * FROM users WHERE id = '${userId}'`;

// GOOD: Parameterized query
const user = await db.query('SELECT * FROM users WHERE id = $1', [userId]);

// GOOD: ORM with parameterized input
const user = await prisma.user.findUnique({ where: { id: userId } });

失效的认证

// Password hashing
import { hash, compare } from 'bcrypt';

const SALT_ROUNDS = 12;
const hashedPassword = await hash(plaintext, SALT_ROUNDS);
const isValid = await compare(plaintext, hashedPassword);

// Session management
app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: true,
    secure: true,
    sameSite: 'lax',
    maxAge: 24 * 60 * 60 * 1000,
  },
}));

跨站脚本(XSS)

// BAD: Rendering user input as HTML
element.innerHTML = userInput;

// GOOD: Use framework auto-escaping (React does this by default)
return <div>{userInput}</div>;

// If you MUST render HTML, sanitize first
import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(userInput);

失效的访问控制

// Always check authorization, not just authentication
app.patch('/api/tasks/:id', authenticate, async (req, res) => {
  const task = await taskService.findById(req.params.id);

  // Check that the authenticated user owns this resource
  if (task.ownerId !== req.user.id) {
    return res.status(403).json({
      error: { code: 'FORBIDDEN', message: 'Not authorized' }
    });
  }

  const updated = await taskService.update(req.params.id, req.body);
  return res.json(updated);
});

输入验证模式

在边界处进行模式(Schema)校验

import { z } from 'zod';

const CreateTaskSchema = z.object({
  title: z.string().min(1).max(200).trim(),
  description: z.string().max(2000).optional(),
  priority: z.enum(['low', 'medium', 'high']).default('medium'),
  dueDate: z.string().datetime().optional(),
});

app.post('/api/tasks', async (req, res) => {
  const result = CreateTaskSchema.safeParse(req.body);
  if (!result.success) {
    return res.status(422).json({
      error: {
        code: 'VALIDATION_ERROR',
        message: 'Invalid input',
        details: result.error.flatten(),
      },
    });
  }
  const task = await taskService.create(result.data);
  return res.status(201).json(task);
});

限流

import rateLimit from 'express-rate-limit';

// General API rate limit
app.use('/api/', rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100,
  standardHeaders: true,
  legacyHeaders: false,
}));

// Stricter limit for auth endpoints
app.use('/api/auth/', rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 10,
}));

密钥管理

.env files:
  ├── .env.example  → Committed (template with placeholder values)
  ├── .env          → NOT committed (contains real secrets)
  └── .env.local    → NOT committed (local overrides)

.gitignore must include:
  .env
  .env.local
  .env.*.local
  *.pem
  *.key

提交前始终检查:

git diff --cached | grep -i "password\|secret\|api_key\|token"

安全审查清单

  • [ ] 密码使用 bcrypt/scrypt/argon2 哈希(salt rounds ≥ 12)
  • [ ] 会话令牌为 httpOnly、secure、sameSite
  • [ ] 登录有限流
  • [ ] 每个端点都检查用户权限
  • [ ] 用户只能访问自己的资源
  • [ ] 所有用户输入都在边界处校验
  • [ ] SQL 查询已参数化
  • [ ] HTML 输出已编码/转义
  • [ ] 代码或版本控制中无密钥
  • [ ] 敏感字段已从 API 响应中排除
  • [ ] 已配置安全响应头(CSP、HSTS 等)
  • [ ] CORS 限制为已知来源
  • [ ] 依赖已审计漏洞
  • [ ] 错误消息不暴露内部信息

验证

在实现与安全相关的代码后:

  • [ ] npm audit 未显示严重(critical)或高危(high)漏洞
  • [ ] 源代码或 git 历史中无密钥
  • [ ] 所有用户输入都在系统边界处校验
  • [ ] 每个受保护端点都检查了认证与授权
  • [ ] 响应中包含安全响应头
  • [ ] 错误响应不暴露内部细节
  • [ ] 认证端点已启用限流