Перейти к содержимому
← Каталог golang CSRF

CSRF: Обход проверки Referer-заголовка

Приложение использует проверку заголовка Referer вместо CSRF-токена. Обойди проверку и смени email администратора.

mediumgolangPro
Задача
# CSRF: Обход проверки Referer-заголовка ## Сценарий Вы проводите аудит безопасности интернет-магазина **SecureShop**. В админ-функционале есть эндпоинт смены email пользователя `POST /profile/change-email`. Разработчик решил «защититься от CSRF без токенов» — он проверяет HTTP-заголовок `Referer` через подстроку `strings.Contains`. Логика автору казалась бронебойной: «если Referer содержит наш домен — запрос свой». На самом деле такая проверка тривиально обходится: достаточно разместить вредоносную страницу по URL, в любом месте пути которого встречается имя домена жертвы. У приложения есть бот-администратор, который проверяет жалобы через `/report` — он откроет любую переданную страницу. ## Цель 1. Найдите эндпоинт смены email и убедитесь, что он защищён только проверкой `Referer`. 2. Подготовьте HTML-payload с авто-сабмит формой, нацеленной на этот эндпоинт. 3. Разместите payload на хостинге так, чтобы итоговый URL содержал имя целевого домена в пути (`/secureshop.local/...`). 4. Через `/report` доставьте URL боту-администратору. Бот откроет страницу, и его браузер отправит `Referer`, содержащий нужную подстроку — обработчик примет запрос как «свой». 5. Заберите флаг — после смены email в почтовом ящике admin (`/email`) появится письмо «Admin Email Changed» с флагом. ## Теория **Referer-based CSRF protection** — попытка защититься от cross-site запросов через анализ заголовка `Referer`, который браузер прикрепляет к запросам, отправленным с одной страницы на другую. Идея в теории звучит правильно: «если Referer не содержит мой домен — значит запрос пришёл с чужого сайта». На практике подход хрупок: * `strings.Contains` ищет подстроку **где угодно** в URL — атакующий просто включает имя домена жертвы в путь своего сайта (`https://attacker.com/secureshop.local/exploit.html`). * Проверка по поддомену атакующего (`secureshop.local.attacker.com`) — если код использует префикс/суффикс, его обходят зеркальной техникой. * Браузер может вообще не отправить `Referer` (например, при `meta name="referrer" content="no-referrer"` или переходе с `https://` на `http://`) — тогда либо запрос проходит без проверки, либо легитимный пользователь получает ошибку. Корректная защита от CSRF не строится на `Referer`. Стандартные решения: **CSRF-токен** (синхронизированный с сессией), **Double-Submit Cookie** (токен в cookie + такое же значение в форме), `SameSite=Strict`/`Lax` cookie, требование кастомного HTTP-заголовка для JSON API. **Уязвимый паттерн:** ```go func (h *Handler) ChangeEmail(w http.ResponseWriter, r *http.Request) { user := h.getUser(r) if user == nil { /* 401 */ return } // Хрупкая защита: ищем подстроку в Referer. // Достаточно, чтобы имя домена встретилось ГДЕ-УГОДНО в URL атакующего. referer := r.Header.Get("Referer") if !strings.Contains(referer, "secureshop.local") { http.Error(w, "Invalid request origin", 403) return } newEmail := r.FormValue("email") h.db.Exec("UPDATE users SET email=? WHERE id=?", newEmail, user.ID) } ``` ## Точка входа атаки | Параметр | Значение | |----------|----------| | Ваш аккаунт | `demo` / `demo` | | Уязвимый эндпоинт | `POST /profile/change-email` | | Поле формы | `email` | | Доставка боту | `POST /report` | | Где появится флаг | `GET /email` — письмо «Admin Email Changed» | | Exploit Server / hosting | внешний хостинг для HTML-payload (см. панель лабы → вкладка HTML Payload) |
🚧 Сайт в разработке. Полный функционал пока недоступен. Все вопросы — support@hackandfix.ru