【PHP初学者向け】CSRFの対策方法を解説します

今回の記事は、PHPでのCSRF(クロスサイトリクエストフォージェリー)の対策方法についてです。

webアプリケーション作成では、必ず対策が必要になるので、ぜひ覚えてください。

railsから学習した僕は、勝手にrailsがやってくれていたので、最初のうちは全く知りませんでした。。。

それでは、やっていきましょう。

versions
  • PHP 8.0.0

CSRF対策とは何かを知ろう

CSRFってなんですか??

こんな方も多いのではないでしょうか?

こういう時はwikipediaなどをみていきましょう。

CSRF脆弱性とは以下のような攻撃(CSRF攻撃)を可能にする脆弱性を指す[1]:攻撃者はブラウザなどのユーザ・クライアントを騙し、意図しないリクエスト(たとえばHTTPリクエスト)をWebサーバに送信させる。Webアプリケーションがユーザ・クライアントからのリクエストを十分検証しないで受け取るよう設計されている場合、このリクエストを正規のものとして扱ってしまい、被害が発生する。CSRF攻撃はURL[1]、画像の読み込み[1]、XMLHttpRequest[1]などを利用して実行される。

クロスサイトリクエストフォージェリ(フリー百科事典『ウィキペディア(Wikipedia)』)

こんな感じで書いてありますが、webアプリの脆弱性を指し、それに対する対策をすることです。

javascriptなどの言語を使用すると、簡単にinputタグなどを生成できるので、同じページに見えても実は違うページなんてことがあります。

CSRF対策をしていこう

PHPではよくお問い合わせフォームを作成するケースがあるので、今回は簡単なフォームを作成していきます。

その上で、CSRF対策をしていきましょう。

以下がCSRF対策が終わったコードです。

<?php 
session_start();

$page = 1;

if (!empty($_POST['submit'])) {
    $page = 2;
}
var_dump($_SESSION);
?>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <?php if ($page === 1): ?>
        <?php
            if (!isset($_SESSION['csrfToken'])) {
                $csrfToken = bin2hex(random_bytes(32));
                $_SESSION['csrfToken'] = $csrfToken;
            }
            $token = $_SESSION['csrfToken'];
        ?>
        <form action="" method="post">
            <input type="text" name="name" id="name">
            <input type="hidden" name="hidden" id="hidden" value="<?php print($token); ?>">
            <input type="submit" name="submit" id="submit" value="送信する">
        </form>
    <?php endif; ?>

    <?php if ($page === 2): ?>
        <?php if ($_POST['hidden'] === $_SESSION['csrfToken']): ?>
            <p>送信が完了しました</p>
            <?php unset($_SESSION['csrfToken']); ?>
        <?php endif; ?>
    <?php endif; ?>
</body>
</html>

random_bytes関数で暗号を作成しよう

色々と書いてありますが、重要なのは、sessionを使用することと、byteを利用した乱数を使用することです。

sessionに関しては、PHPのsessionについて初学者向けに解説しますをご参考ください。

乱数はとてつもないほどの通り数があるので、人間の予測は不可能です。

だから、暗号に使用されるんですね。

今回は、

bin2hex(random_bytes(32));

32bytesの乱数を用意して、それを16進数の表現に直しています。

まとめ

  • CSRFとは、webブラウザへの攻撃の一種である
  • CSRF対策は、乱数を使用する
  • random_bytes関数で簡単に乱数を用意できる

難しそうに思いますが、こういった対策も関数を使用すれば簡単です。

フレームワークには基本的にCSRF対策がなされているので、意識しなくても大丈夫ですが、覚えておくことに価値があります。

参考

乱数について本気出して考えてみる

bin2hex

random_bytes