Заголовки безопасности и ограничение запросов
Два простых шага заметно повышают защиту API. Первый — защитные заголовки ответа: они говорят браузеру, что запрещено делать с вашим сайтом. Второй — ограничение частоты запросов (rate limiting): один клиент не сможет отправить тысячи запросов в минуту, например перебирая пароли на /login.
Установка
npm install @fastify/helmet @fastify/rate-limitHelmet
Плагин @fastify/helmet добавляет к каждому ответу набор защитных заголовков. Подключите его в src/app.js:
// src/app.js
import helmet from '@fastify/helmet';
app.register(helmet);Выполните curl -i http://localhost:3000/posts — среди заголовков появятся, например, x-content-type-options: nosniff и content-security-policy.
| Заголовок | Что запрещает |
|---|---|
Content-Security-Policy | Загрузку скриптов и стилей с чужих адресов |
X-Content-Type-Options | Угадывание типа файла браузером |
X-Frame-Options | Встраивание сайта в чужой iframe |
Strict-Transport-Security | Обращение к сайту без HTTPS |
Для чистого JSON API настройки по умолчанию подходят. Если сервер отдаёт и HTML-страницы, политику contentSecurityPolicy настраивают под свои скрипты.
Ограничение запросов
Плагин @fastify/rate-limit считает запросы с каждого IP-адреса и после превышения лимита отвечает кодом 429 «Too Many Requests»:
// src/app.js
import rateLimit from '@fastify/rate-limit';
app.register(rateLimit, {
max: 100,
timeWindow: '1 minute',
});Теперь с одного адреса можно сделать не больше 100 запросов в минуту. В каждом ответе есть заголовки x-ratelimit-limit и x-ratelimit-remaining — лимит и сколько запросов осталось.
Свой лимит для маршрута
Маршрут входа стоит ограничить строже. Лимит задаётся в опции config маршрута в src/routes/auth.js:
// src/routes/auth.js
app.post('/login', {
config: {
rateLimit: { max: 5, timeWindow: '1 minute' },
},
}, async (request) => {
// ...проверка логина и выдача токена
});Шестая попытка входа за минуту получит ответ 429, и подбирать пароль станет бессмысленно.
Порядок подключения
Оба плагина подключайте в src/app.js раньше маршрутов: rate-limit применяет лимиты к маршрутам, которые объявлены после него.
Частая ошибка
За обратным прокси (например, nginx) все запросы приходят с одного адреса — адреса прокси, — и лимит срабатывает сразу для всех посетителей. Включите опцию trustProxy: true при создании приложения, чтобы Fastify брал настоящий IP клиента из заголовка X-Forwarded-For.