ログイン不要で書き込めるフォームにおけるCSRF対策

CSRFにおける脅威

IPAの「安全なWebサイトの作り方」に記載されている、CSRFの”発生しうる脅威”には以下の2つが挙げられています。

  • ログイン後の利用者のみが利用可能なサービスの悪用
  • ログイン後の利用者のみが編集可能な情報の改ざん、新規登録

これは典型的なCSRFですが、認証機能の存在しないWebサイトでもCSRFは発生します。

例えば匿名掲示板や企業のお問い合わせフォームにCSRF脆弱性がある場合、被害者は攻撃者のサイトにアクセスしただけで、犯罪予告を投稿してしまう危険性があります。

トレンドマイクロdigicertのCSRFの紹介ページ、徳丸本にもその旨が記載されています。

本書ではCSRF脆弱性の影響を受けるのは認証機能のあるサイトとしていますが、特殊な状況では認証機能がないサイトでもCSRF攻撃を受ける可能性があります。2012年6月29日、横浜市のサイトに犯行予告声明が投稿され…

体系的に学ぶ 安全なWebアプリケーションの作り方 第2版

なお、海外のQAサイトを覗くと、認証不要のフォームはそもそも誰もが投稿できるものであるため、CSRFが発生する余地はないという意見がいくつかありました。そういう考えの人もいるということですね。

認証不要のフォームはCSRF未対策の場合が多い

CSRFはログイン後の操作が不正に行われるというインパクトが強く、歴史的にも認証不要のフォームに対するCSRFはせいぜい悪戯程度しかできないと見なされていたようで、対策が一切されていないフォームは多いです。

例えばWordPressのコメントも実はCSRF脆弱性があります。

これは10年以上前から指摘されていたそうですが、未だ修正されていません。

CSRF対策用のプラグインまであります。WordPressのCSRF脆弱性について詳細が知りたい方は以下の記事を参考にしてください。

WordPressのコメントフォームにはCSRF脆弱性が存在する

パブリックフォームのCSRF対策

ログイン不要で投稿できるフォームのCSRF対策は、通常のCSRF対策と変わりません。

例えばCSRFトークンを埋め込む方式の場合、以下のようにCookieとしてセッションIDを発行し、トークンをinput要素とセッション変数に埋め込むだけです。

<?php
    session_start();
    $token = bin2hex(openssl_random_pseudo_bytes(24));
    $_SESSION['token'] = $token;
?>
<body>
    <form action="post.php" method="POST">
        <textarea name="comment"></textarea>
        <input type="hidden" name="token" value="<?= htmlspecialchars($token, ENT_COMPAT, 'UTF-8'); ?>">
        <input type="submit" value="login">
    </form>
</body>
<?php
    session_start();
    $token = filter_input(INPUT_POST, 'token');
    if (empty($_SESSION['token']) || $token !== $_SESSION['token']) {
        die('投稿失敗');
    }
?>
<body>
    <p>コメントを投稿しました:<?= htmlspecialchars($_POST['comment'], ENT_QUOTES, 'UTF-8'); ?></p>
</body>

上記のようなコードであれば、クロスサイトからの投稿はトークンが存在しないため失敗します。

セッションIDはログイン処理にしか使えないと勘違いしている人もいますが、そんなことはありません。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)