HTML-формы, отправка данных и CSRF

Формы — главный способ получить данные от пользователя, а защита CSRF и объект Request делают эту работу безопасной и удобной.

Суть: форма отправляет данные методом POST на маршрут, в шаблоне обязательна директива @csrf, а в контроллере данные читаются через объект Request.

Любое взаимодействие — регистрация, добавление товара, отправка комментария — это форма. Браузер посылает её содержимое на сервер методом POST, а контроллер должен эти данные принять и обработать. Laravel делает процесс простым и безопасным: объект Request даёт удобный доступ ко всем полям, а встроенная защита CSRF предотвращает подделку запросов.

CSRF (Cross-Site Request Forgery) — это атака, при которой злоумышленник заставляет браузер жертвы отправить запрос от её имени. Laravel защищается токеном: каждая форма должна содержать секретный токен, который проверяется на сервере. Без него запрос отклоняется с ошибкой 419.

Форма и контроллер

{{-- resources/views/products/create.blade.php --}}
<form method="POST" action="/products">
    @csrf   {{-- обязательный токен защиты --}}

    <input type="text" name="name" placeholder="Название">
    <input type="number" name="price" placeholder="Цена">
    <button type="submit">Сохранить</button>
</form>
<?php
use Illuminate\Http\Request;

class ProductController extends Controller
{
    public function store(Request $request)
    {
        // чтение данных формы
        $name  = $request->input('name');
        $price = $request->input('price');

        // или сразу нужные поля
        $data = $request->only(['name', 'price']);

        Product::create($data);

        return redirect('/products');
    }
}

Как работает под капотом: защита CSRF

Директива @csrf вставляет в форму скрытое поле с токеном, привязанным к сессии пользователя. Когда форма приходит на сервер, middleware VerifyCsrfToken сравнивает токен из формы с тем, что хранится в сессии. Совпали — запрос проходит; нет — отклоняется. Сторонний сайт не знает токен жертвы, поэтому подделать запрос не может.

  ЗАЩИТА CSRF
  -----------
  1. Сервер кладёт токен в сессию и в форму (@csrf)
  2. Пользователь отправляет форму -> токен едет с ней
  3. Middleware сверяет: форма.token == сессия.token ?
        совпало  -> 200 запрос обработан
        нет      -> 419 отклонено

  Чужой сайт токена не знает -> подделка невозможна

Для методов PUT, PATCH, DELETE HTML-формы не поддерживают эти глаголы напрямую, поэтому используется директива @method:

<form method="POST" action="/products/5">
    @csrf
    @method('DELETE')   {{-- подменяет метод на DELETE --}}
    <button>Удалить</button>
</form>

Смоделируем проверку CSRF-токена на Python.

Попробуй сам ▶

# Проверка CSRF-токена (упрощённо)
session_token = 'secret-abc-123'   # токен в сессии пользователя

def handle_request(form_token):
    if form_token == session_token:
        return '200 OK — данные сохранены'
    return '419 — CSRF token mismatch'

print(handle_request('secret-abc-123'))   # своя форма
print(handle_request('fake-token'))        # чужой сайт
print(handle_request(None))                # токен забыли

Частые ошибки

  • Забыть @csrf. Самая частая причина ошибки 419 — отсутствие токена в форме.
  • Доверять данным формы. Любой ввод нужно валидировать (следующий урок) — пользователь может прислать что угодно.
  • Метод GET для изменения данных. Создание и удаление — это POST/DELETE, а не GET.

Best practices

  • Используйте $request->only([...]) или валидированные данные вместо $request->all().
  • После успешной обработки делайте redirect() (паттерн POST-Redirect-GET) — это защищает от повторной отправки.
  • Для PUT/PATCH/DELETE в формах применяйте @method.

Объект Request умеет гораздо больше, чем просто читать поля. Метод $request->has('coupon') проверяет наличие поля, $request->filled('coupon') — что оно не пустое, а $request->boolean('subscribe') аккуратно приводит галочку чекбокса к настоящему булеву значению (ведь из формы приходит строка «on» или «1»). Для загрузки файлов есть $request->file('avatar') и метод store(), сохраняющий файл в настроенное хранилище. Важно помнить про идемпотентность: операции, меняющие данные, должны идти через POST/PUT/DELETE, а GET остаётся для безопасного чтения — поисковые роботы и предзагрузка браузера могут «прокликать» GET-ссылки, и если по GET что-то удаляется, последствия будут печальными. Поэтому ссылки-действия (удалить, оформить) всегда оформляют формами с нужным методом, а не обычным тегом ссылки.

Итог: формы отправляют данные методом POST, директива @csrf защищает от подделки, а объект Request даёт удобный доступ к полям. Дальше — как проверять корректность этих данных через валидацию.

Проверьте себя
1. Зачем в форме нужна директива @csrf?
AДля красоты
BВставляет токен защиты от подделки запросов (CSRF)
CСоздаёт маршрут
DПодключает базу
2. Через что контроллер читает данные отправленной формы?
AЧерез глобальную переменную
BЧерез объект Request (например $request->input())
CЧерез файл .env
DЧерез миграцию