Защита микросервисов от CSRF: что нужно знать и как это сделать
CSRF-атаки — реальная угроза для микросервисов, особенно если они используют сессии или авторизацию через cookie. В Node.js защита от подделки запросов требует чёткого понимания механизма и правильной реализации. В статье — как настроить защиту, какие ошибки чаще всего допускают, и почему некоторые подходы не работают.
Что такое CSRF-атака и почему она опасна для микросервисов
CSRF (Cross-Site Request Forgery) — это атака, при которой злоумышленник заставляет пользователя выполнить нежелательное действие на сайте, где он уже авторизован. В микросервисной архитектуре это может означать изменение данных, отправку сообщений или изменение состояния ресурса. Угроза не в том, что пользователь попадает на вредоносный сайт, а в том, что его браузер может выполнить запрос к защищённому сервису, если у него есть действующая сессия.
Микросервисы, особенно если они используют cookie-авторизацию, уязвимы к CSRF. Даже если API защищён токеном, который выдаётся при входе, злоумышленник может использовать подделку запроса, если он знает, как выглядит требуемый HTTP-запрос. Это особенно актуально, когда микросервисы не используют строгую проверку токенов или когда токены не проверяются на каждом запросе.
Если вы думаете, что CSRF — это проблема только в веб-приложениях, то вы ошибаетесь. Микросервисы, которые используют cookie для сессий, также уязвимы. Например, если пользователь заходит на сайт, где он авторизован, и открывает вредоносную страницу, браузер может автоматически отправить POST-запрос к вашему микросервису, если тот не проверяет токен. Это не требует взлома — просто используется существующая сессия.
CSRF‑атака работает, даже если злоумышленник не знает пользовательские данные. Он просто использует его сессию. Если у пользователя есть активная сессия, а микросервис не проверяет токен, то злоумышленник может выполнить любое изменяющее действие, которое может быть сделано через POST-запрос. Это может быть изменение пароля, отправка сообщения или даже удаление данных.
Если вы не уверены, что у вас есть CSRF-уязвимость, то посмотрите на то, как работает аутентификация. Если вы используете cookie для сессии, и токен не проверяется на каждом изменяющем запросе, то вы, скорее всего, уязвимы. Это не зависит от того, используете ли вы REST или GraphQL — если сессия работает через cookie, то CSRF-атака возможна.
Ключевой механизм: CSRF-токены и их роль
Для защиты от CSRF-атак используется генерация и валидация CSRF-токенов. Токен — это случайная строка, которая генерируется на стороне сервера и передаётся клиенту. При каждом изменяющем запросе клиент должен отправить этот токен. Сервер проверяет, что токен совпадает с тем, который был выдан при сессии. Если токен не совпадает или отсутствует — запрос отклоняется.
В Node.js это реализуется через middleware, который генерирует токен и проверяет его при каждом изменяющем запросе. Важно, чтобы токен был связан с конкретной сессией, иначе злоумышленник может использовать токен, сгенерированный для другого пользователя. Это требует хранения токена в сессии, а не в cookie, чтобы избежать подделки. Некоторые библиотеки, такие как csurf, предлагают готовую реализацию, но требуют внимательной настройки.
Если вы используете csurf, он не работает с REST‑архитектурой по умолчанию. В REST-архитектуре токен не передаётся через форму, а через заголовок. Поэтому csurf может не подойти, если вы используете API, где токен передаётся через X-CSRF-Token. В этом случае нужно либо использовать csurf с настройкой, либо реализовать защиту вручную.
Если вы не хотите использовать csurf, то можно реализовать защиту вручную. Это включает генерацию токена при каждом GET-запросе, хранение его в сессии, и проверку при каждом POST-запросе. Важно, чтобы токен был уникальным для каждой сессии и не мог быть повторно использован. Это можно сделать, например, с помощью crypto.randomBytes в Node.js.
CSRF‑токен дополняет, а не заменяет остальные меры безопасности. Он не защищает от XSS, не защищает от утечки токена, и не работает, если токен передаётся через заголовок. Поэтому его нужно использовать в сочетании с другими мерами, такими как SameSite и Secure-атрибуты.
Реализация защиты: middleware и настройки
В Express.js для защиты от CSRF можно использовать middleware csurf. Он генерирует токен при каждом GET-запросе к странице, который затем должен быть отправлен вместе с POST-запросом. Важно, чтобы токен был включён в форму или передавался через заголовок, если используется API. Однако csurf не подходит для всех случаев — особенно если микросервисы используют REST-архитектуру, где токен не может быть передан через форму. В таких случаях требуется ручная реализация.
Другой подход — использование sameSite-атрибута в cookie. Установка SameSite=Strict или SameSite=Lax ограничивает отправку куки с внешних сайтов. Это помогает защитить от CSRF, но не заменяет CSRF-токены. Некоторые браузеры уже не поддерживают SameSite=None без Secure, что делает SameSite-настройку важной, но не достаточной мерой. SameSite не поддерживается старыми браузерами и не покрывает все возможные сценарии.
Если вы используете csurf, то важно настроить его правильно. Например, нужно указать, какие методы нужно защищать (только POST, PUT, DELETE), и какие пути исключить. Также нужно настроить, где хранить токен — в сессии или в cookie. Если токен хранится в cookie, то он может быть подделан, если злоумышленник знает его значение. Поэтому лучше хранить токен в сессии.
Если вы не используете csurf, то можно реализовать защиту вручную. Это включает генерацию токена при каждом GET-запросе, хранение его в сессии, и проверку при каждом POST-запросе. Важно, чтобы токен был уникальным для каждой сессии и не мог быть повторно использован. Это можно сделать, например, с помощью crypto.randomBytes в Node.js.
csurf не решает все проблемы. Он не работает с API, где токен передаётся через заголовок. В этом случае нужно использовать SameSite и Secure-атрибуты, а также проверку токена вручную. Это требует больше усилий, но обеспечивает большую безопасность.
Ошибки, которые делают микросервисы уязвимыми
Одна из самых распространённых ошибок — использование CSRF-токена только для GET-запросов. Это не имеет смысла, так как GET-запросы не изменяют состояние. Токен должен проверяться только при запросах, которые изменяют данные — POST, PUT, DELETE. Если токен проверяется на всех запросах, это создаёт избыточную нагрузку и может привести к ошибкам в работе.
Ещё одна ошибка — передача CSRF-токена через заголовок X-CSRF-Token. Это может показаться безопасным, но злоумышленник может использовать JavaScript на вредоносном сайте, чтобы отправить запрос с этим заголовком. Браузер не проверяет, откуда пришёл заголовок, и отправит его, если сессия активна. Поэтому токен должен быть связан с сессией, а не просто передаваться через заголовок. Также важно, чтобы токен был уникальным для каждой сессии и не мог быть повторно использован.
Третья ошибка — использование одного токена для всех сессий. Это делает токен подделываемым. Если токен одинаков для всех пользователей, то злоумышленник может использовать его для атаки. Токен должен быть уникальным для каждой сессии, иначе он не защищает.
Четвёртая ошибка — не проверка токена на каждом изменяющем запросе. Если токен проверяется только при первом запросе, то злоумышленник может использовать тот же токен для последующих запросов. Это делает защиту бесполезной. Токен должен проверяться на каждом изменяющем запросе.
Пятая ошибка — использование SameSite=None без Secure. Это делает cookie уязвимыми к CSRF, так как браузер может отправить куки с внешних сайтов. Важно, чтобы SameSite был установлен на Strict или Lax, и чтобы Secure-атрибут был включён.
Порядок действий: как настроить защиту
Первое, что нужно сделать, — определить, используете ли вы cookie-авторизацию. Если да, то вы уязвимы к CSRF. Если нет, то CSRF-атака не имеет смысла. В этом случае нужно использовать JWT-токен в Authorization-заголовке. Это устраняет необходимость в CSRF-токенах.
Второе — настроить SameSite-атрибут в cookie. Установите SameSite=Strict или SameSite=Lax. Это ограничит отправку куки с внешних сайтов. Также установите Secure-атрибут, чтобы куки отправлялись только по HTTPS.
Третье — реализовать CSRF-токен. Генерируйте токен при каждом GET-запросе, храните его в сессии, и проверяйте при каждом изменяющем запросе. Используйте crypto.randomBytes для генерации токена. Убедитесь, что токен уникален для каждой сессии.
Четвёртое — настроить middleware для проверки токена. Используйте csurf или реализуйте защиту вручную. Убедитесь, что токен проверяется на каждом изменяющем запросе. Исключите из проверки те пути, которые не требуют защиты.
Пятое — протестировать защиту. Создайте вредоносную страницу, которая отправляет POST-запрос к вашему микросервису. Убедитесь, что запрос отклоняется, если токен не совпадает. Проверьте, что токен не может быть повторно использован.
- Определить, используете ли вы cookie-авторизацию
- Настроить `SameSite` и `Secure`-атрибуты
- Генерировать CSRF-токен при каждом GET-запросе
- Хранить токен в сессии
- Проверять токен на каждом изменяющем запросе
- Настроить middleware для проверки токена
- Протестировать защиту
Типовые ошибки и как их избежать
Одна из самых распространённых ошибок — использование одного токена для всех сессий. Это делает токен подделываемым. Если токен одинаков для всех пользователей, то злоумышленник может использовать его для атаки. Токен должен быть уникальным для каждой сессии, иначе он не защищает.
Ещё одна ошибка — передача CSRF-токена через заголовок X-CSRF-Token. Это может показаться безопасным, но злоумышленник может использовать JavaScript на вредоносном сайте, чтобы отправить запрос с этим заголовком. Браузер не проверяет, откуда пришёл заголовок, и отправит его, если сессия активна. Поэтому токен должен быть связан с сессией, а не просто передаваться через заголовок.
Третья ошибка — не проверка токена на каждом изменяющем запросе. Если токен проверяется только при первом запросе, то злоумышленник может использовать тот же токен для последующих запросов. Это делает защиту бесполезной. Токен должен проверяться на каждом изменяющем запросе.
Четвёртая ошибка — использование SameSite=None без Secure. Это делает cookie уязвимыми к CSRF, так как браузер может отправить куки с внешних сайтов. Важно, чтобы SameSite был установлен на Strict или Lax, и чтобы Secure-атрибут был включён.
Как проверить, что защита работает
Чтобы проверить, что защита от CSRF работает, нужно создать вредоносную страницу, которая отправляет POST-запрос к вашему микросервису. Убедитесь, что запрос отклоняется, если токен не совпадает. Проверьте, что токен не может быть повторно использован.
Если вы используете csurf, то проверьте, что он настроен правильно. Убедитесь, что он проверяет токен на каждом изменяющем запросе. Проверьте, что токен генерируется при каждом GET-запросе. Убедитесь, что токен хранится в сессии, а не в cookie.
Если вы реализуете защиту вручную, то проверьте, что токен уникален для каждой сессии. Убедитесь, что токен проверяется на каждом изменяющем запросе. Проверьте, что токен не может быть повторно использован.
Если вы не уверены, что защита работает, то протестируйте её. Создайте вредоносную страницу, которая отправляет POST-запрос к вашему микросервису. Убедитесь, что запрос отклоняется, если токен не совпадает. Проверьте, что токен не может быть повторно использован.
Что делать, если уже сломалось
Если вы обнаружили, что у вас есть CSRF-уязвимость, то нужно действовать немедленно. Сначала отключите все изменения, которые могут быть выполнены через POST-запросы. Затем настройте защиту. Убедитесь, что токен проверяется на каждом изменяющем запросе.
Частые вопросы
Как работает CSRF-токен?
CSRF-токен — это случайная строка, генерируемая сервером и передаваемая клиенту. При каждом изменяющем запросе клиент должен отправить этот токен. Сервер проверяет, что токен совпадает с тем, который был выдан при сессии. Если токен не совпадает или отсутствует, запрос отклоняется.
Какие методы защиты от CSRF существуют?
Основные методы: CSRF-токены, настройка `SameSite`-атрибута в cookie, использование `Authorization`-заголовка с JWT, проверка токена на стороне сервера. Каждый метод имеет свои плюсы и минусы.
Можно ли использовать CSRF-токены в микросервисах?
Да, но только если микросервисы используют cookie-авторизацию. Если используется JWT в `Authorization`-заголовке, CSRF-токены не нужны. CSRF‑токены дополняют, но не заменяют такие меры, как флаги `Secure` и `HttpOnly`.
Что делать, если токен не проверяется?
Если CSRF-токен не проверяется, это означает, что атака может быть успешной. Нужно убедиться, что токен генерируется, передаётся и проверяется на каждом изменяющем запросе. Также важно проверить, что токен связан с сессией и не может быть повторно использован.
Какие ошибки чаще всего допускают при защите от CSRF?
Ошибки: использование одного токена для всех сессий, передача токена через заголовок, не проверка токена на каждом изменяющем запросе, использование `SameSite=None` без `Secure`.
Как проверить, что защита работает?
Нужно создать вредоносную страницу, которая отправляет POST-запрос к вашему микросервису. Убедитесь, что запрос отклоняется, если токен не совпадает. Проверьте, что токен не может быть повторно использован.
Источники
- web-kokteil.ru — https://web-kokteil.ru/csrf-%D0 %B0 %D1 %82 %D0 %B0 %D0 %BA%D0 %B0-%D1 %87 %D1 %82 %D0 %BE-%D1 %8D%D1 %82 %D0 %BE-%D1 %82 %D0 %B0 %D0 %BA%D0 %B8 %D0 %B5
- systemanalyst.life — https://systemanalyst.life/knowledge-base/api-authentication
- api7.ai — https://api7.ai/ru/blog/csrf-and-solutions
- www.dev-notes.ru — https://www.dev-notes.ru/articles/security/csrf-preventing/
- www.compilenrun.com — https://www.compilenrun.com/docs/framework/express/express-security/express-cookie-security/


