はじめに
Laravelなどを使わず、シンプルなPHPでフォームを作る場合、csrf対策を自力で行う必要があります。
まあそんな機会は多くないかもしれませんが、覚えておいて損はない、、!
ということでやっていきましょう。
入力画面、確認画面、結果画面、3画面の一般的なフォームで実装していきます。
入力画面
ランダムな文字列で生成したトークンを、セッションに格納します。
すでにセッションに存在する場合は、そちらを使います。
entry.php
<?php
session_start(); //セッション開始
$token = '';
if ( isset( $_SESSION[ 'token' ] ) || !empty( $_SESSION[ 'token' ] ) ) {
$token = $_SESSION['token']; //セッションにすでにあるとき
} else {
$token = bin2hex(random_bytes(32)); //トークンを生成
$_SESSION['token'] = $token; //セッションにトークンを格納
}
type=“hidden”で隠したinputに、トークンを置き、他の入力内容とともにsubmitします。
entry.php
<form action="./confirm.php" method="POST">
<input type="hidden" name="token" value="<?php echo $token; ?>"> //隠しフィールドにトークンを設置し、フォーム送信時に一緒に送る
<input type="submit" value="確認">
</form>
確認画面
POSTで送られてきたトークンがセッションにあるトークンと一致するかをチェックしています。
一致しない場合は、入力画面に戻す。
一致する場合は、またinputに設置して送信します。
confirm.php
<?php
session_start(); //セッション開始
//トークンチェック
if (isset($_POST['token']) && isset($_SESSION['token'])) {
$token = $_POST['token'];
if ($token != $_SESSION['token']) { //トークンが一致しない場合は処理を中止
header("Location: entry.php");
echo ('アクセスが中断されました。');
exit();
}
} else { //トークンが存在しない場合は処理を中止する
header("Location: entry.php");
echo ('不正なアクセスです');
exit();
}
confirm.php
<form action='./complete.php' method='POST'>
<input type='hidden' name='token' value='<?php $token; ?>'>
<input type="submit" value="送信する">
</form>
結果画面
結果画面でも、確認画面と同じようにチェックすればOKです。
complete.php
<?php
session_start(); //セッション開始
//トークンチェック
if (isset($_POST['token']) && isset($_SESSION['token'])) {
$token = $_POST['token'];
if ($token != $_SESSION['token']) { //トークンが一致しない場合は処理を中止
header("Location: entry.php");
echo ('アクセスが中断されました。');
exit();
}
} else { //トークンが存在しない場合は処理を中止する
header("Location: entry.php");
echo ('不正なアクセスです');
exit();
}
最後に処理が完了したら、
session_destroy();
で、セッションを破棄することをお忘れなきよう!
以上、これにて完成となります。
おわりに
いかがだったでしょうか。
Laravelだと、@csrfと書くだけですが、Laravelが使えない場合でも、意外と簡単に作ることができます。
ぜひ参考にしてみてください!