CodeWalk

Node.js 中的输入验证与防注入最佳实践

作者:Yahuda · 2026-05-30 12:55

请列举 Node.js 后端开发中常见的输入验证策略(参数校验/SQL 注入防护/命令注入防护/原型链污染防护)。

回答

Yahuda

1. 参数校验

  • 使用 joi/zod/yup 进行结构化和类型校验
const schema = z.object({
  email: z.string().email(),
  age: z.number().min(0).max(150),
});
const result = schema.safeParse(req.body);
  • 白名单验证:只接受预期的字段(避免多余参数注入)

2. SQL 注入防护

// ❌ 错误:字符串拼接
const sql = `SELECT * FROM users WHERE id = ${req.params.id}`;

// ✅ 正确:参数化查询
const sql = 'SELECT * FROM users WHERE id = $1';
db.query(sql, [req.params.id]); // PostgreSQL 参数化
  • ORM(Prisma/TypeORM/Sequelize)自带参数化查询
  • 不使用 escape() 或手动过滤(容易遗漏)

3. 命令注入防护

// ❌ 危险
const { exec } = require('child_process');
exec(`ping -c 1 ${req.body.host}`); // host = ; rm -rf /

// ✅ 安全:使用 execFile + 白名单
const { execFile } = require('child_process');
execFile('ping', ['-c', '1', sanitizedHost]);

4. 原型链污染防护

// ❌ 危险
function merge(target, source) {
  for (let key in source) {
    target[key] = source[key];
  }
}
merge({}, JSON.parse('{"__proto__":{"isAdmin":true}}'));

// ✅ 防护
function safeMerge(target, source) {
  for (let key in source) {
    if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue;
    target[key] = source[key];
  }
}
  • 使用 Object.create(null) 创建无原型对象
  • 使用 JSON.parse 默认不安全,lodash.merge 已修复此问题

5. 其他:路径遍历防护(path.resolve + 前缀检查)、正则 DoS 防护(限制输入长度)。