以下のような流れで、PHPにてPOST処理の二重送信対策を行っています。
1.画面表示時に、ランダムな文字列でトークンを発行。
2.発行したトークンをセッション変数に格納。
3.フォームのhidden要素に発行したトークンをセット。
4.POSTされた時に、「POSTされたhidden要素のトークン」と、「セッションに格納されているトークン」を比較。
5.両者が一致していた場合は、処理を行う。
具体的なコードは、以下の通りです。
(page.php?id=xxxx)
PHP
1<?php 2//POSTされたhidden要素のトークンを取得 3$post_token = isset($_POST['token']) ? $_POST['token'] : ''; 4 5//セッションに格納されたトークンを取得 6$session_token = isset($_SESSION['token']) ? $_SESSION['token'] : ''; 7 8//セッションに格納されたトークンを破棄 9unset($_SESSION['token']); 10 11//POSTされたhidden要素のトークンとセッションに格納されているトークンを比較 12if($post_token != '' && $session_token == $post_token){ 13 //トークン一致 14 //(ここで登録処理) 15}else{ 16 //トークン無し or トークン不一致 17 //(処理キャンセル) 18} 19 20//二重送信対策用トークンを発行 21$token = rtrim(base64_encode(openssl_random_pseudo_bytes(32)),'='); 22 23//トークンをセッションに格納 24$_SESSION['token'] = $token; 25 26?> 27 28<!DOCTYPE html> 29<html lang="ja"> 30<head>xxxx記事詳細</head> 31<body> 32 33<form method="POST"> 34<input type="text" name="comment"> 35<input type="hidden" name="token" value="<?php echo $token;?>"> 36<input type="submit" value="送信"> 37</form> 38 39</body> 40</html>
以上のコードで、同画面上では正常に二重送信対策が出来たのですが、タブブラウザで複数タブを開いた時に問題がありました。
例えば、ブログの「記事一覧ページ」にアクセスし、最初に「各記事ページ(page.php?id=xxx)」を複数タブで開いておいて、それぞれのタブで記事にコメントしたい、というケースがあると思います。
理想は、タブ毎に二重送信をチェックにしたいのですが、上記コードだと新しく記事詳細ページを開く度に、セッションに格納するトークンが更新されてしまいます。
そうすると、最後に開いたタブ以外のタブでは、hidden要素にセットしたトークンとセッションに格納したトークンが相違してしまう事になり、二重送信とみなされてしまいます。
対策として、以下の二つを考えました。
1.$_SESSION[$page_id][$token]のような形で、ページ毎にトークンを格納する。
(懸念点)ページを開くたびにトークンが追加され、セッション変数が肥大化してしまう。
2.POST先を別画面にし、別画面での処理後に元の画面にリダイレクトさせる。
別画面ではトークンチェックは行わず、POST判定、リファラー判定のみを行う。
(懸念点)ページリロード対策にはなるが、根本的な二重POST対策にはなっていない。
※javascript側で、submitされた時にsubmitボタンをDisable化し、二重リクエスト自体は送られないようにはしております。
他にベストな対策方法がありましたら、教えていただけませんでしょうか。
回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/05/18 03:09
退会済みユーザー
2017/05/18 03:39