Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
440
Help us understand the problem. What is going on with this article?
@mpyw

とっても簡単なCSRF対策

More than 1 year has passed since last update.

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>
...
440
Help us understand the problem. What is going on with this article?
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
mpyw
古い記事はそのまま参考にしないようにご注意ください
synapse
Synapseは、オンラインサロンサービスにおけるパイオニアとして、かつて存在していたスタートアップです。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
440
Help us understand the problem. What is going on with this article?