关于 input-validation
input-validation 是面向开发者的安全技能,强调在系统边界验证不可信数据。它列出验证标准、基于模式的做法、风险信号,以及应对跳过验证的常见借口的方法。
主要功能
- 01在入口处验证外部数据
- 02检查类型、格式、范围和必填项
- 03采用基于模式的验证方式
- 04识别不安全的输入处理模式
- 05反驳跳过验证的常见理由
适用场景
- 01写入数据库前验证 HTTP 请求数据
- 02检查文件、环境变量和 API 输入
- 03审查代码中的未验证输入
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yanko-belov/ code-craft --skill input-validation安装后在 Claude Code 中输入/input-validation确认已加载。
详细介绍
输入验证
概述
永远不要信任输入。在系统边界验证所有内容。
所有外部数据都可能是恶意或格式错误的。在数据入口处进行验证,并在输入无效时快速失败。
适用场景
- 处理 HTTP 请求正文、参数和标头
- 读取文件或环境变量
- 接收来自外部 API 的数据
- 任何接收不可信输入的函数
铁律
NEVER use external input without explicit validation.
没有例外:
- 不能因为“前端会验证”
- 不能因为“这是内部 API”
- 不能因为“我们信任来源”
- 不能因为“这只是一个简单字段”
检测:信任隐患
如果你在直接使用输入,请立即停止:
// ❌ VIOLATION: Trusting input
app.post('/users', async (req, res) => {
const { email, age } = req.body; // Direct destructure - no validation
await db.users.create({ email, age });
res.json({ success: true });
});
问题:
email可能为空、为 null,或不是字符串age可能为负数、字符串,或缺失- 根据使用方式,可能出现 SQL 注入、XSS
正确做法:在边界处验证
// ✅ CORRECT: Validate with schema
import { z } from 'zod';
const createUserSchema = z.object({
email: z.string().email('Invalid email format'),
age: z.number().int().min(13).max(120),
name: z.string().min(1).max(100),
});
app.post('/users', async (req, res) => {
// Validate
const result = createUserSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({
error: 'Validation failed',
details: result.error.flatten().fieldErrors
});
}
// Now data is typed and validated
const { email, age, name } = result.data;
await db.users.create({ email, age, name });
res.status(201).json({ success: true });
});
验证规则
始终验证:
- 类型:它是字符串、数字还是布尔值?
- 格式:电子邮件是否有效?UUID 是否有效?
- 范围:最小/最大长度是多少?数值边界是多少?
- 必填:它是否存在?
- 清理:必要时移除危险字符
验证库示例:
// Zod (recommended for TypeScript)
const schema = z.object({
id: z.string().uuid(),
email: z.string().email(),
age: z.number().min(0).max(150),
role: z.enum(['user', 'admin']),
tags: z.array(z.string()).max(10),
});
// Yup
const schema = yup.object({
email: yup.string().email().required(),
age: yup.number().positive().integer(),
});
// class-validator
class CreateUserDto {
@IsEmail()
email: string;
@IsInt()
@Min(13)
age: number;
}
抵御施压的应对方案
1. “前端会验证”
施压说法:“表单已经验证过这些数据了”
**回应:**前端验证是为了改善用户体验。后端验证是为了安全。攻击者可以绕过前端。
**行动:**无论前端是否验证,都要在后端进行验证。
2. “这是内部 API”
施压说法:“只有我们的服务会调用这个端点”
**回应:**内部服务也会有漏洞。纵深防御要求在所有地方进行验证。
**行动:**也要验证内部 API 的输入。
3. “我们信任来源”
施压说法:“这些数据来自合作伙伴的 API”
**回应:**对方的 API 可能有漏洞、遭到入侵或更改格式。不要信任任何人。
**行动:**使用外部 API 响应之前先进行验证。
4. “只是一个简单字段”
施压说法:“这只是一个字符串,能出什么问题?”
**回应:**字符串可能为空、过长,也可能包含脚本、SQL 或空字节。
**行动:**明确“有效”的定义并强制执行。
危险信号——立即停止并重新考虑
- 未经验证就执行
const { x } = req.body - 对输入使用
any类型 - 输入无效时没有错误响应
- “客户端会正确发送这些数据”
- 解析输入时没有使用 try/catch
以上情况都意味着:添加验证。
快速参考
| 输入类型 | 验证内容 |
|---|---|
| 电子邮件 | 格式、长度、必填 |
| 密码 | 长度、复杂度 |
| ID | 格式(uuid/int)、是否存在 |
| 数字 | 类型、范围、是否为整数? |
| 字符串 | 长度、模式、清理 |
| 数组 | 长度、数组项验证 |
| 对象 | 模式验证 |
常见借口(均不成立)
| 借口 | 实际情况 |
|---|---|
| “前端会验证” | 攻击者可以绕过前端。 |
| “内部 API” | 内部也会有漏洞。 |
| “我们信任来源” | 来源可能遭到入侵。 |
| “简单字段” | 简单字段也会导致复杂漏洞。 |
| “验证很慢” | 验证比安全漏洞造成的损失更快。 |
| “TypeScript 类型就够了” | 类型在运行时会消失。 |
核心要点
验证所有输入。不要信任任何内容。数据无效时快速失败。
每个外部边界都应该进行明确验证。使用模式验证库。对无效输入返回清晰的错误消息。绝不要让未经验证的数据进入系统。
评论
支持 Markdown