log > Slim(php)3でCSRF対策

Slim(php)3でCSRF対策

Slim3を相変わらず触っている。

SlimでCsrfを行うには、公式に用意されているCsrfライブラリを使う。

基本的な使い方は、公式ドキュメントとSlimの生みの親であるRob Allenのブログに書いてあるので、こちらを参考に使えばいいだろう。

個人的にはslim3-skeletonで使いたかったので、その方法を調べていた。

composer require slim/csrfでインストールした後は、middleware.phpで、宣言して$app->add($guard)のようにする。失敗したときの処理はsetFailureCallable内に書く。ここでは、別のクラスで判定したりするために変数を設定するだけにとどめる。

// middleware.php
$guard = new Slim\Csrf\Guard();
$guard->setFailureCallable(function ($request, $response, $next) {
    $request = $request->withAttribute("csrf_status", false);
    return $next($request, $response);
});
$app->add($guard);

Action(Controller)で、判定を行って失敗時の処理を行う。(本当ならViewを呼び出してrenderするべきだった。)

// SaveAction.php
    if ($request->getAttribute('csrf_status') === false) {
        $failed = <<<EOT
<!DOCTYPE html>
<html>
<head><title>不正な投稿が行われました</title></head>
<body>
    <h1>投稿をやり直してください</h1>
    <p>このエラーは意図しない投稿が行われた場合や、前に戻るを使った場合に出るエラーです。最初の画面から投稿をやり直してください。</p>
</body>
</html>
EOT;
        return $response->write($failed);
    }

送信元のActionは次のように書いた。

// HomeAction.php
$name = $request->getAttribute('csrf_name');
$value = $request->getAttribute('csrf_value');

$this->view->render($response, 'home.twig', ['name' => $name, 'value' => $value]);

テンプレートは次のように書いた。

// home.twig
<form action="{{ path_for('save') }}" method="post" accept-charset="utf-8">
       <input type="hidden" name="csrf_name" value="{{ name }}">
       <input type="hidden" name="csrf_value" value="{{ value }}">
       <input type="text" name="impression" value="" placeholder="感想">
       <input type="submit" name="" value="送信">
</form>

本来ならcsrf_namecsrf_valueもとれるみたいなんだけど、面倒だし公式ドキュメントでもやってないので、まあいいかということにした。

以上。