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