Help us understand the problem. What is going on with this article?

とっても簡単なCSRF対策

CSRFおよびその対策の仕組みに関してはこちら↓

これで完璧!今さら振り返る CSRF 対策と同一オリジンポリシーの基礎 - Qiita

この記事は,PHPにおけるワンタイムトークンを用いた実装例を示すものです。執筆日が少々古いものになるのでご了承ください。

コメント欄の議論に関するまとめ

以下,XSS脆弱性が存在しない前提.この脆弱性があるとあらゆるCSRF対策がほとんど意味をなさなくなるので,まずここから潰しておくこと.

セッション固定攻撃に対する対策

  • ログイン後にsession_regenerate_idを必ず実行する.
  • ログアウト後にsession_destroyを必ず実行する.

CSRF攻撃に対する対策

  • セッションIDを抜かれることは原則的には無いが,セッションIDをそのままトークンに用いるのは避けたほうが無難.
  • ワンタイムトークンにはF5リロードでの誤作動を防止する意味合いもあるが,必ずしもワンタイム性が求められるわけではない.固定トークンでも十分なセキュリティは保証される.
  • トークンによる対策が施されていない場合,GETであってもPOSTであってもCSRFは実行可能なので,それは議論の対象ではない.

実装

以前はワンタイムトークン推奨にしていましたが,意向が変わってきたので固定トークンのサンプルに差し替えておきます.

クラス定義
class CsrfValidator {

    const HASH_ALGO = 'sha256';

    public static function generate()
    {
        if (session_status() === PHP_SESSION_NONE) {
            throw new \BadMethodCallException('Session is not active.');
        }
        return hash(self::HASH_ALGO, session_id());
    }

    public static function validate($token, $throw = false)
    {
        $success = self::generate() === $token;
        if (!$success && $throw) {
            throw new \RuntimeException('CSRF validation failed.', 400);
        }
        return $success;
    }

}

使い方

フォームに埋め込むとき
<input type="hidden" name="token" value="<?=CsrfValidator::generate()?>">
検証するとき(返り値チェックタイプ)
<?php

if (!CsrfValidator::validate(filter_input(INPUT_POST, 'token'))) {
    header('Content-Type: text/plain; charset=UTF-8', true, 400);
    die('CSRF validation failed.');
}

// 続きの処理

?>
<!DOCTYPE html>
...
検証するとき(例外タイプ)
<?php

try {

    CsrfValidator::validate(filter_input(INPUT_POST, 'token'), true);

    // 続きの処理…

} catch (\RuntimeException $e) {

    header('Content-Type: text/plain; charset=UTF-8', true, $e->getCode() ?: 500);
    die($e->getMessage());

}

?>
<!DOCTYPE html>
...
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした