Что такое CSRF токен?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое CSRF-токен?
CSRF-токен (Cross-Site Request Forgery Token) — это уникальный, секретный и непредсказуемый токен, который генерируется сервером и передаётся клиенту для защиты от атак типа «межсайтовая подделка запроса» (CSRF). Этот токен подтверждает, что запрос, отправленный клиентом, был инициирован легитимным пользователем с авторизованной сессии, а не злоумышленником с другого сайта.
Как работает CSRF-токен?
Механизм защиты с использованием CSRF-токена включает следующие шаги:
- Генерация токена — сервер создаёт криптографически случайный токен (обычно 32+ байт) и привязывает его к сессии пользователя. Пример генерации в Go:
import (
"crypto/rand"
"encoding/base64"
)
func generateCSRFToken() (string, error) {
token := make([]byte, 32)
if _, err := rand.Read(token); err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(token), nil
}
- Передача токена клиенту — токен внедряется в HTML-формы как скрытое поле или добавляется в заголовки AJAX-запросов. Пример формы:
<form method="POST" action="/transfer">
<input type="hidden" name="csrf_token" value="abc123...">
<input type="text" name="amount">
<button type="submit">Перевести</button>
</form>
- Верификация токена — при получении POST/PUT/DELETE запроса сервер сравнивает токен из запроса с токеном в сессии пользователя:
func verifyCSRFToken(sessionToken, requestToken string) bool {
return subtle.ConstantTimeCompare(
[]byte(sessionToken),
[]byte(requestToken),
) == 1
}
- Отказ в обработке — если токены не совпадают или отсутствуют, запрос отклоняется с ошибкой 403 Forbidden.
Почему CSRF-токены эффективны?
- Непредсказуемость — злоумышленник не может угадать токен для конкретной сессии
- Привязка к сессии — каждый пользователь получает уникальный токен
- Требование присутствия — атакующий сайт не может прочитать токен из-за политики Same-Origin Policy
- Простота реализации — минимальные накладные расходы
Реализация в Go-фреймворках
Большинство современных фреймворков предоставляют встроенную защиту:
- Gin — через middleware
gin.csrf:
import "github.com/gin-gonic/gin"
import "github.com/utrack/gin-csrf"
func main() {
r := gin.Default()
r.Use(csrf.Middleware(csrf.Options{
Secret: "secret-key",
ErrorFunc: func(c *gin.Context) {
c.String(403, "CSRF token mismatch")
c.Abort()
},
}))
}
- Gorilla/csrf — популярная standalone библиотека:
import "github.com/gorilla/csrf"
func main() {
CSRF := csrf.Protect(
[]byte("32-byte-long-auth-key"),
csrf.Secure(false), // true для HTTPS
)
http.ListenAndServe(":8000", CSRF(mux))
}
Лучшие практики использования
- Токен должен быть уникальным для каждой сессии — перегенерация при аутентификации
- Использовать Constant-Time сравнение — для предотвращения timing-атак
- Защищать все изменяющие состояние операции — POST, PUT, DELETE, PATCH
- Не использовать GET для изменяющих операций — даже с токеном
- Реализовать токен как для форм, так и для AJAX — через заголовки
X-CSRF-Token - Учитывать особенности SPA — передача токена через cookies с флагом
SameSite=Strict
Альтернативы и дополнения
- SameSite cookies — современные браузеры поддерживают атрибут
SameSite, ограничивающий отправку cookies - Двойная отправка cookies — токен хранится в cookie и сравнивается с значением в теле запроса
- Custom заголовки — требование наличия специальных заголовков для AJAX-запросов
CSRF-токен остается фундаментальным механизмом защиты веб-приложений, несмотря на появление дополнительных мер. В сочетании с другими практиками безопасности (HTTPS, валидация ввода, принцип минимальных привилегий) он создает надежный барьер против межсайтовых атак, сохраняя при этом удобство использования для легитимных пользователей.