Статьи

Защита от CSRF в Slim 3 PHP Framework

В дополнение к базовой платформе Slim , мы также поставляем ряд дополнений, которые полезны для конкретных типов проблем. Одним из них является Slim-Csrf, который обеспечивает защиту CSRF .

Это промежуточное ПО, которое устанавливает токен в сеансе для каждого запроса, который затем можно установить в виде скрытого поля ввода в форме. Когда форма отправляется, промежуточное программное обеспечение проверяет, что значение в поле формы соответствует значению, сохраненному в сеансе. Если они совпадают, то все в порядке, но если они не совпадают, возникает ошибка.

В простейшем случае вам нужно запустить сеанс и добавить промежуточное программное обеспечение:

session_start();
$app->add(new Slim\Csrf\Guard());

Затем из заданного маршрута можно создать форму и добавить два скрытых поля: одно для имени токена и одно для его значения:

$app->get('/', function ($request, $response, $args) {
    // CSRF token name and value
    $name = $request->getAttribute('csrf_name');
    $value = $request->getAttribute('csrf_value');

    // Render a form
    $html = <<<EOT
<!DOCTYPE html>
<html>
<head><title>CSRF test</title></head>
<body>
    <form method="POST" action="/process">
        <input type="hidden" name="csrf_name" value="$name">
        <input type="hidden" name="csrf_value" value="$value">
        <input type="text" name="name" placeholder="Name">
        <input type="submit" value="Go">
    </form>
</body>
</html>
EOT;

    return $response->write($html);
});

Если вы запустите это в браузере и просмотрите исходный код, вы увидите что-то вроде этого:

Slim CSRF Посмотреть исходный код

Обновите, и вы увидите разные значения для полей csrf_name и csrf_value, что означает, что пользователь может иметь несколько открытых вкладок и отправлять без каких-либо проблем.

Для тестирования я создал простой вызываемый маршрут:

$app->post('/process', function ($request, $response, $args) {
    return $response->write("Passed CSRF check.");
});

Нажатие кнопки отправки формы приведет к отображению «Пройденной проверки CSRF». Если вы обновите и подтвердите сообщение, вы увидите «Ошибка проверки CSRF!» и код состояния HTTP будет 400.

Настройка сбоя CSRF

Вполне вероятно, что вы захотите настроить отображение ошибок CSRF, поскольку текстовое сообщение об ошибке не очень удобно для пользователя! Чтобы изменить это, укажите вызываемый класс для класса Guard, который имеет ту же сигнатуру, что и промежуточное программное обеспечение: `
function ($ request, $ response, $ next). Промежуточное программное обеспечение должно возвращать ответ.

Это позволяет вам предоставить пользовательскую страницу ошибки:

$guard = new Slim\Csrf\Guard();
$guard->setFailureCallable(function ($request, $response, $next) {
    return $response->write(<<<EOT
<!DOCTYPE html>
<html>
<head><title>CSRF test</title></head>
<body>
    <h1>Error</h1>
    <p>An error occurred with your form submission.
       Please start again.</p>
</body>
</html>
EOT);
});
$app->add($guard);

Поскольку вызываемый сбой имеет сигнатуру промежуточного программного обеспечения, вы также можете установить флаг в $ request и затем обработать сбой CSRF. Вызываемый сбой будет выглядеть примерно так:

$guard->setFailureCallable(function ($request, $response, $next) {
    $request = $request->withAttribute("csrf_result", 'FAILED');
    return $next($request, $response);
});

Теперь ваш маршрут может решить, что делать:

$app->post('/process', function ($request, $response, $args) {
    if (false === $request->getAttribute('csrf_result')) {
        // Deal with error here and update $response as appropriate
    } else {
        // successfully passed CSRF check
        $response->write("Passed CSRF check.");
    }
    return $response;
});

Это очень мощный и удивительно простой в настройке.

Резюме

Гибкость вызываемого сбоя позволяет вам обрабатывать сбой проверки CSRF наиболее подходящим для вашего приложения способом и является очень мощной функцией этого промежуточного программного обеспечения.

Поскольку он совместим с PSR-7, вы можете использовать промежуточное программное обеспечение независимо от Slim с любой системой диспетчеризации промежуточного программного обеспечения PSR-7, которая использует сигнатуру промежуточного программного обеспечения ($ request, $ response, $ next), где возвращается ответ.