トークンで二度押し防止

トークンを使ってフォーム送信時の多重登録の制御

確認

確認時にtokenを発行。

PHP

// 確認トークン発行 // PHP7以降 $_SESSION['token']['confirm'] = bin2hex(random_bytes(32)); // PHP5.3以降 // $_SESSION['token']['confirm'] = bin2hex(openssl_random_pseudo_bytes(32)); $view->assign('token_confirm', $_SESSION['token']['confirm']); $view->display('confirm.tpl');

hiddenで送信。

Smarty

<input type="hidden" name="token_confirm" value="{$token_confirm}">

完了

PHP

// 完了時全体処理開始 // ---1 $token_confirm = filter_input(INPUT_POST, 'token_confirm'); // 確認トークンが発行されていない、または確認トークンがPOSTされていない if (empty($_SESSION['token']['confirm']) || empty($token_confirm)) { // ---2 // エラー処理(入力画面に戻す処理など) } // 確認トークンが一致、完了トークンが発行されていない if (hash_equals($_SESSION['token']['confirm'], $token_confirm) && empty($_SESSION['token']['complete'])) { try { // ---3 // 処理(DB登録、メール送信などの処理) // 処理成功 // 完了トークン発行 $_SESSION['token']['complete'] = bin2hex(random_bytes(32)); } catch (Exception $e) { // ---4 // 処理失敗(エラー発生のメッセージなど) } } // 完了トークンが発行されていない if (empty($_SESSION['token']['complete'])) { // ---5 // エラー処理(入力画面に戻す処理など) } // 確認トークンを更新 $_SESSION['token']['confirm'] = bin2hex(random_bytes(32)); // 完了時全体処理完了 // ---6 $view->display('complete.tpl');

正常な処理においては 1 > 3 > 6の順で通過。
確認トークンを更新することで二度押し、リロードやリロードされた場合は、 1 > 6の順となる。

確認トークンが異常な場合は 1 > 2 の順で処理停止。
例外発生した場合は 1 > 4 の順で処理停止。
完了トークンが無効な場合は 1 > 5 の順で処理停止。SESSIONに保存された確認トークンとPOSTされた確認トークンが一致しないと完了トークンが無効となる。

全てのトークンは入力時(修正で戻ったときも同様に)にunsetして初期化する。

二度押し防止対策として確認-完了についての解説になっていますが、CSRF対策でトークンを利用するのであれば、入力画面(必要な箇所があれば全てに)でも制御を施すようにします。

最新の記事

プロフィール

流されるままにウェブ業界で仕事しています。主にLAPP環境でPHPを書いています。最近はjQueryで遊んでいます。
※動作確認について