2011-11-30

PHPで2重登録、2重ポスト、CSRF対策

こんな感じで実装できると思う。




■ input.php ... 入力画面など
<?php
//  セッションを開始する
session_start();

//  ワンタイムチケットを生成する。
$ticket = md5(uniqid(rand(), true));

//  生成したチケットをセッション変数へ保存する。
$_SESSION['ticket'] = $ticket;
?>
<html>
<head>
<title>サンプル登録画面</title>
</head>
<body>
<form action="regist.php" method="POST">
<input type="text" name="UserName" value="">
<input type="submit" value="regist">
<!--  生成したワンタイムチケットを隠しフィールドとして、
      登録処理へPOSTする  -->
<input type="hidden" name="ticket" value="<?=$ticket?>">
</form>
</body>
</html>




■ regist.php ... 登録処理など
<?php
//  セッションを開始する
session_start();

//  ポストされたワンタイムチケットを取得する。
$ticket = isset($_POST['ticket'])    ? $_POST['ticket']    : '';

//  セッション変数に保存されたワンタイムチケットを取得する。
$save   = isset($_SESSION['ticket']) ? $_SESSION['ticket'] : '';

//  セッション変数を解放し、ブラウザの戻るボタンで戻った場合に備え
//  る。
unset($_SESSION['ticket']);

//  ポストされたワンタイムチケットの中身が空だった、または、ポス
//  トすらされてこなかった場合、不正なアクセスとみなして強制終了す
//  る。
if ($ticket === '') {

    die('不正なアクセスです');

}

//  ポストされたワンタイムチケットとセッション変数から取得したワン
//  タイムチケットが同じ場合、正常にポストされたとみなして処理を行
//  う。
if ($ticket === $save) {

    echo 'Normal Access';

}
//  ブラウザの戻るボタンで戻った場合は、セッション変数が存在しない
//  ため、2重送信とみなすことができる。
//  また、不正なアクセスの場合もワンタイムチケットが同じになる確率
//  は低いため、不正アクセス防止にもなる。
else {

    echo 'Dual Posted';

}
?>

6 件のコメント:

  1. 二重送信で苦心していましたが、助かりました。
    ありがとうございます。

    返信削除
    返信
    1. こちらこそ、コメント残していただいてありがとうございます。
      わたしもまだまだ未熟ですし、記述したことももっと良い方法があるかも
      しれませんが、お一人でも多くのPGさんとSEさんが助かっていただければ
      幸です。

      削除
  2. どうやっても DualPostになってしまいます。
    $_SESSION['ticket']が空になっている様です。

    返信削除
  3. 最初のvalue=の部分をを、
    echo $ticket とする事で動く様になりました。お騒がせしました。

    返信削除
  4. 初心者で、二重送信の防止などわかりませんでしたので、参考にさせていただきます。
    ありがとうございました。

    返信削除
  5. //2重登録、2重ポスト、CSRF対策

    とても助かります。ほかのサイトでは、unset部分が記載されていないのに
    「これでうまくいきます」と書いてあったりと、勉強する側としては途方に暮れていましたが
    このサイトを見て、やっぱりか!という気持ちになりました。おかげさまでタイトルの仕組みを
    しっかりと勉強できた気がします。永久保存したい内容でした。

    本当にありがとうございます!

    返信削除

Chatの「メッセージは投稿者によって削除されました」を非表示にする方法

Chrome拡張機能を自作してやってみよう! ♪できるかな できるかな ・・・ 無理ぽ (´・ω・`) iframeの中に、実際のメッセージのやり取りが表示されるので、 $(function(){ $('iframe[name^="spa...