Экранирование и санитизация ввода
Экранирование (escaping) преобразует специальные символы в безопасные представления для конкретного контекста (HTML, SQL, URL); санитизация (sanitization) удаляет или заменяет опасные части ввода. Вместе они предотвращают инъекции и XSS.
Зачем нужно
Пользовательский ввод — основной вектор атак: XSS, SQLi, Command Injection, Path Traversal. Правило: данные от пользователя никогда не должны интерпретироваться как код или команды. Контекст экранирования важен: HTML-экранирование не защитит от SQLi.
Где используется
- HTML-вывод: предотвращение XSS при рендеринге данных пользователя
- SQL-запросы: параметризация (экранирование через driver)
- URL-параметры: encoding при формировании ссылок
- Файловые пути: предотвращение Path Traversal
- Shell-команды: ограничение или полный отказ от
execс пользовательским вводом
Основной контент
HTML escaping (XSS prevention)
// Встроенный в большинство шаблонизаторов
// Handlebars: {{value}} — автоэкранирование, {{{value}}} — без (опасно!)
// React: JSX автоматически экранирует {value}
// Ручное HTML-экранирование (если нужно)
function escapeHtml(str) {
const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
return str.replace(/[&<>"']/g, ch => map[ch]);
}
// Для разрешённого HTML (комментарии, rich text) — только DOMPurify
const DOMPurify = require('isomorphic-dompurify');
const safeHtml = DOMPurify.sanitize(userHtml, {
ALLOWED_TAGS: ['p', 'b', 'i', 'a', 'ul', 'li'],
ALLOWED_ATTR: ['href'],
});
URL encoding
// Кодирование параметров URL
const query = encodeURIComponent(userInput);
const url = `https://api.example.com/search?q=${query}`;
// URLSearchParams — безопасный способ построения query string
const params = new URLSearchParams({ q: userInput, page: 1 });
const url = `https://api.example.com/search?${params}`;
Path Traversal prevention
const path = require('path');
function safeFilePath(baseDir, userInput) {
// Нормализуем путь
const resolved = path.resolve(baseDir, userInput);
// Проверяем, что файл внутри базовой директории
if (!resolved.startsWith(path.resolve(baseDir))) {
throw new Error('Path traversal detected');
}
return resolved;
}
// Безопасно:
const filePath = safeFilePath('/uploads', req.params.filename);
// Атака "../../etc/passwd" будет отклонена
Input validation с Zod
const { z } = require('zod');
const UserSchema = z.object({
name: z.string.min(1).max(100).trim(),
email: z.string.email.toLowerCase(),
age: z.number.int.min(0).max(150),
website: z.string.url.optional,
});
app.post('/api/users', (req, res) => {
const result = UserSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ errors: result.error.issues });
}
const validated = result.data; // Типобезопасные данные
});
Частые ошибки
- Экранирование только на фронтенде — бэкенд должен делать то же самое
- Использование
innerHTML = userInputвместоtextContent— XSS - Самописное HTML-экранирование — легко пропустить edge-case. Используйте DOMPurify
- Санитизация только при вводе, но не при выводе — данные могут прийти из других источников
Связанные темы
- _MOC Безопасность
- SQL Injection
- Prepared Statements -- защита от SQL-инъекций
- Insecure Deserialization