Skip to main content

input-validation

Validate and sanitize all user input to prevent XSS, path traversal, command injection, and malformed data. Covers Zod, Joi, class-validator, Laravel validation, and Python Pydantic. Use when building forms, API endpoints, file uploads, or fixing injection vulnerabilities beyond SQL.

来源信息

仓库
afu-it/security-for-vibecoders
最近来源活动
2026年5月28日 10:34
检测到的 SKILL.md 语言
英语
星标
3
分支
1

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
input-validation
description
Validate and sanitize all user input to prevent XSS, path traversal, command injection, and malformed data. Covers Zod, Joi, class-validator, Laravel validation, and Python Pydantic. Use when building forms, API endpoints, file uploads, or fixing injection vulnerabilities beyond SQL.
version
1.0
# Input Validation Validate and sanitize ALL user input at every entry point. This covers Finding #2 (path traversal) and extends beyond SQL injection to XSS, command injection, and data integrity. ## The Rule **NEVER trust user input. ALWAYS validate type, length, format, and range on the server side.** ## Attack Vectors Prevented | Attack | How it works | Validation fix | |--------|-------------|----------------| | XSS | Inject `<script>` into rendered HTML | HTML-encode output, validate no HTML in text fields | | Path Traversal | `../../etc/passwd` in file paths | Whitelist allowed paths, reject `..` | | Command Injection | `; rm -rf /` in shell commands | Never pass user input to shell, use spawn with args array | | SSRF | User-controlled URLs fetch internal services | Whitelist allowed domains, block private IPs | | Prototype Pollution | `__proto__` in JSON keys | Strip dangerous keys, use `Object.create(null)` | | File Upload Abuse | `.php` file uploaded as "image" | Validate MIME type + magic bytes, not just extension | ## Framework Patterns ### Node.js with Zod (Recommended) ```typescript import { z } from 'zod'; // Define strict schemas 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), role: z.enum(['user', 'admin']), }); // Validate at API boundary app.post('/users', async (req, res) => { const result = CreateUserSchema.safeParse(req.body); if (!result.success) { return res.status(400).json({ error: 'Validation failed', issues: result.error.issues.map(i => ({ field: i.path.join('.'), message: i.message, })), }); } const validated = result.data; // Type-safe, validated await createUser(validated); }); ``` ### Path Traversal Prevention BAD: ```typescript app.get('/files/:filename', (req, res) => { const file = path.join('/uploads', req.params.filename); res.sendFile(file); // ../../etc/passwd works! }); ``` GOOD: ```typescript import path from 'path'; const UPLOAD_DIR = path.resolve('/uploads'); app.get('/files/:filename', (req, res) => { const filename = path.basename(req.params.filename); // Strip directory traversal const filePath = path.resolve(UPLOAD_DIR, filename); // Verify resolved path is still within allowed directory if (!filePath.startsWith(UPLOAD_DIR)) { return res.status(403).json({ error: 'Access denied' }); } res.sendFile(filePath); }); ``` ### XSS Prevention BAD: ```typescript // Server-side rendering with raw user input app.get('/profile', (req, res) => { res.send(`<h1>Welcome, ${req.query.name}</h1>`); }); ``` GOOD: ```typescript import { encode } from 'html-entities'; app.get('/profile', (req, res) => { const safeName = encode(req.query.name || ''); res.send(`<h1>Welcome, ${safeName}</h1>`); }); // Or better: use a template engine with auto-escaping (EJS, Handlebars, React) ``` ### File Upload Validation ```typescript import { fileTypeFromBuffer } from 'file-type'; const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp']; const MAX_SIZE = 5 * 1024 * 1024; // 5MB async function validateUpload(file: Buffer, filename: string) { // Check size if (file.length > MAX_SIZE) { throw new Error('File too large (max 5MB)'); } // Check actual file type via magic bytes (not extension!) const type = await fileTypeFromBuffer(file); if (!type || !ALLOWED_TYPES.includes(type.mime)) { throw new Error(`Invalid file type. Allowed: ${ALLOWED_TYPES.join(', ')}`); } // Generate safe filename (never use user-provided filename directly) const safeFilename = `${crypto.randomUUID()}.${type.ext}`; return safeFilename; } ``` ### Command Injection Prevention BAD: ```typescript import { exec } from 'child_process'; exec(`convert ${userFilename} output.png`); // Shell injection! ``` GOOD: ```typescript import { execFile } from 'child_process'; // execFile does NOT use shell, so injection is impossible execFile('convert', [userFilename, 'output.png']); ``` ### Laravel / PHP ```php // Form request validation class StoreUserRequest extends FormRequest { public function rules(): array { return [ 'email' => ['required', 'email:rfc,dns', 'max:255'], 'name' => ['required', 'string', 'max:100', 'regex:/^[a-zA-Z\s\'-]+$/'], 'age' => ['required', 'integer', 'min:13', 'max:150'], 'role' => ['required', Rule::in(['user', 'admin'])], 'avatar' => ['nullable', 'image', 'mimes:jpg,png,webp', 'max:5120'], ]; } } ``` ### Python with Pydantic ```python from pydantic import BaseModel, EmailStr, Field, validator import re class CreateUser(BaseModel): email: EmailStr name: str = Field(min_length=1, max_length=100) age: int = Field(ge=13, le=150) role: Literal['user', 'admin'] @validator('name') def name_must_be_safe(cls, v): if not re.match(r"^[a-zA-Z\s'-]+$", v): raise ValueError('Name contains invalid characters') return v # Usage in FastAPI @app.post("/users") async def create_user(user: CreateUser): # user is already validated and type-safe pass ``` ## Validation Checklist For every API endpoint, verify: - [ ] All input fields have type validation (string, number, boolean) - [ ] String fields have max length limits - [ ] Numeric fields have min/max range - [ ] Enum fields use allowlists (not blocklists) - [ ] Email fields use proper email validation - [ ] URL fields validate protocol (https only) and domain - [ ] File uploads check magic bytes, not just extension - [ ] Path parameters cannot traverse directories - [ ] No user input is passed to shell commands - [ ] No user input is used in dynamic `import()` or `eval()` ## PDPA 2024 Consequence **Seksyen 5(1) dan 5(2) PDPA 2010 (Pindaan 2024):** - Denda sehingga RM1,000,000 - Penjara sehingga 3 tahun Path traversal (Finding #2) allowed attackers to download the entire user database. The developer was charged because input validation is a **basic security measure** that any competent developer should implement.
在 GitHub 查看