前置き
本記事では、laravelを学習しはじめの頃に遭遇する419エラーが出る仕組みをざっくり紹介しています。結論から言うと、laravelのフレームワークが、CSRF対策を行ってくれているために、Httpリクエスト時に必要な情報が抜けているとエラーが表示されるという仕組みです。
※全ての処理を書いてしまうと大変なことになるため、処理のポイントとなる部分のみを端折って記載していますので、その点はご了承ください。
※セッションの保存先はデフォルトの"file"という前提で記載しています。
csrfとは
公式Documentから引用
クロスサイトリクエストフォージェリは、認証済みユーザーに代わって不正なコマンドを実行する、悪意のある攻撃の一種です。
全体流れ
ブラウザ
"/"へアクセスしてサーバーへリクエスト
サーバー
40字のランダムな文字列データ(暗号)を生成
※後でこの値とフォームから送られてくる_csrfの値を照合する
/vendor/laravel/framework/src/Illuminate/Session/Store
protected function generateSessionId()
{
return Str::random(40);
}
暗号の値をセッションへ保存
/storage/framework/sessions/ へ暗号の値をファイルとして保存する(ファイル名が暗号の値)
/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem
public function put($path, $contents, $lock = false)
{
return file_put_contents($path, $contents, $lock ? LOCK_EX : 0);
}
暗号の値を読み取る
/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem
public function sharedGet($path)
{
$contents = '';
$handle = fopen($path, 'rb');
if ($handle) {
try {
if (flock($handle, LOCK_SH)) {
clearstatcache(true, $path);
$contents = fread($handle, $this->size($path) ?: 1);
flock($handle, LOCK_UN);
}
} finally {
fclose($handle);
}
}
return $contents;
}
htmlの<form>内の<input name= “_token”>のvalueにセット
ブラウザ
リクエストを投げる(/loginへのPOST)
サーバー
formから送られてきたcsrfの値とサーバー側の値が等しいかチェック
/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken
protected function tokensMatch($request)
{
$token = $this->getTokenFromRequest($request);
return is_string($request->session()->token()) &&
is_string($token) &&
hash_equals($request->session()->token(), $token);
}
チェックが完了したら、レスポンスヘッダーに、Cookieをセットしてブラウザに返す。
まとめ
いかがでしたでしょうか。本記事では、laravelを学習しはじめの頃に遭遇する419エラーが出る仕組みをざっくり紹介しています。結論から言うと、laravelのフレームワークが、CSRF対策を行ってくれているために、Httpリクエスト時に必要な情報が抜けているとエラーが表示されるという仕組みです。