← Назад к вопросам
Как обеспечить failover и отказоустойчивость в Node.js приложении?
3.0 Senior🔥 171 комментариев
#DevOps и инфраструктура#Архитектура и паттерны
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как защитить Node.js приложение от XSS-атак?
XSS (Cross-Site Scripting) — это **атака, при которой вредоносный JavaScript код выполняется в браузере пользователя**. В Backend мы должны очищать (санитизировать) пользовательский ввод.
Основная угроза
<!-- ✗ УЯЗВИМО: пользователь вводит -->
<script>alert('Hacked!')</script>
<!-- Ваше приложение выводит в HTML -->
<h1>Welcome, <script>alert('Hacked!')</script></h1>
<!-- Скрипт выполнится в браузере! -->
Решение 1: Экранирование HTML
const escapeHtml = (str: string): string => {
const map: { [key: string]: string } = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return str.replace(/[&<>"']/g, (char) => map[char]);
};
const userInput = '<script>alert("xss")</script>';
const escaped = escapeHtml(userInput);
console.log(escaped); // <script>alert("xss")</script>
Решение 2: Использовать helmet.js
import helmet from 'helmet';
import express from 'express';
const app = express();
// Установить secure headers
app.use(helmet());
// helmet помогает защитить от:
// - XSS (через Content-Security-Policy)
// - Clickjacking
// - SQL Injection
// - MIME-type sniffing
Решение 3: Content-Security-Policy
import helmet from 'helmet';
const app = express();
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", 'trusted-cdn.com'],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:', 'https:'],
fontSrc: ["'self'", 'fonts.googleapis.com'],
frameSrc: ["'none'"],
objectSrc: ["'none'"]
}
}));
// CSP запретит выполнение inline скриптов
// <script>alert('xss')</script> не выполнится!
Решение 4: Использовать xss пакет
import xss from 'xss';
const userInput = `<img src=x onerror="alert('xss')">Click me`;
const cleaned = xss(userInput);
console.log(cleaned); // <img src="x">Click me
// Опции
const whiteList = {
a: ['href', 'title'],
img: ['src', 'alt'],
strong: [],
em: []
};
const strict = xss(userInput, { whiteList });
Решение 5: Валидация и санитизация
import validator from 'validator';
import sanitizeHtml from 'sanitize-html';
app.post('/comment', (req, res) => {
const { comment } = req.body;
// 1. Валидация (проверить формат)
if (!validator.isLength(comment, { min: 1, max: 1000 })) {
return res.status(400).json({ error: 'Invalid comment length' });
}
// 2. Санитизация (очистить опасный контент)
const cleaned = sanitizeHtml(comment, {
allowedTags: ['b', 'i', 'em', 'strong', 'a'],
allowedAttributes: {
a: ['href']
},
allowedSchemes: ['https']
});
// 3. Сохранить в БД
db.query('INSERT INTO comments (content) VALUES ($1)', [cleaned]);
res.json({ message: 'Comment saved' });
});
Решение 6: Template Escaping в Express
// app.js
app.set('view engine', 'ejs');
// views/comment.ejs
<div>
<!-- ✓ EJS автоматически экранирует -->
<p><%= comment %></p>
<!-- ✗ Небезопасно: без экранирования -->
<p><%- comment %></p>
</div>
Решение 7: Использовать параметризованные запросы
// ✗ ПЛОХО: SQL Injection + возможный XSS
const query = `SELECT * FROM users WHERE name = '${req.body.name}'`;
db.query(query);
// ✓ ХОРОШО: Параметризованный запрос
db.query('SELECT * FROM users WHERE name = $1', [req.body.name]);
Полный пример защищённого приложения
import express from 'express';
import helmet from 'helmet';
import sanitizeHtml from 'sanitize-html';
import validator from 'validator';
const app = express();
// Security headers
app.use(helmet());
// CSP
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"]
}
}));
// Rate limiting
import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100
});
app.use(limiter);
// Input validation
app.post('/comments', (req, res) => {
const { comment } = req.body;
// Validate
if (!validator.isLength(comment, { min: 1, max: 1000 })) {
return res.status(400).json({ error: 'Invalid' });
}
// Sanitize
const cleaned = sanitizeHtml(comment, {
allowedTags: ['b', 'i', 'strong'],
allowedAttributes: {}
});
// Store
db.query(
'INSERT INTO comments (content, user_id) VALUES ($1, $2)',
[cleaned, req.user.id]
);
res.json({ message: 'Saved' });
});
Чеклист XSS защиты
- Helmet.js — установить security headers
- Content-Security-Policy — запретить inline скрипты
- Input validation — проверить формат
- HTML escaping — экранировать спецсимволы
- Template escaping — использовать правильный синтаксис в шаблонах
- Sanitization — удалить опасный HTML
- Rate limiting — защита от brute force
- HTTPS — шифрование
- Secure cookies — HttpOnly, Secure флаги
- Regular updates — обновлять зависимости