これを正しく理解していれば、リクエストごとにトークンを設定しているようです。私の推測では、古いページにはまだ古いトークンが残っています。トークンが自動的に吹き飛ばされる前に、トークンが設定されているかどうかを確認します。
if (isset($_SESSION['token'])){
//do nothing
} else{
$_SESSION['token'] = md5(rand());
}
編集 質問に答えるため。
「トークン」のキーを1つだけ使用するのではなく、ブラウザセッションごとにキーを作成します。
$_SESSION[$sessionId] = md5(rand());
もちろん、セッションを使用できない場合、リクエストが新しいタブからのものか古いタブからのものかが実際にはわからないため、これらがいつ発生するかを把握するのがコツです。クエリ文字列を使用して、このパラメータを渡すことができます。基本的に、すべてのリクエストにはこのパラメータが必要です。そうでない場合、セッションをリクエストに関連付けることはできません。
例:
http://www.yoursite.com/somepage.php?sessionid=<some generated id>
最終的に、ユーザーはこれでサルをすることができますが、それを回避する方法があるかどうかはわかりません。
編集2 さて、これがあなたがこれをどのように行うべきかについての私の考えです。そこにいるセキュリティの専門家は、私が専門家ではない前に言ったように、私がこれを間違っている場合は遠慮なく私を炎上させてください、しかし私が何かを提案せずにこれから抜け出すつもりではないようです;-)
CSFRの問題は、悪意のあるユーザーであるBobが別のサイトに要素を作成し、Aliceのブラウザが他のサイトにリクエストを送信する可能性があることです。これは、Aliceが以前にログインしていて、その情報がCookieまたはAliceとして保存されているためです。セッションを介して認識されると、サイトはアリスが要求したかのように要求を実行します。たとえば、アリスの銀行がhttp://www.mybank.com の場合 、その後、ボブは以下を含むフォーラム投稿を作成できます
<img srg="http://www.mybank.com/transferfunds.php?amount=1000&receiver=Bob" />
アリスの銀行は、自分のブラウザが自分だと思ってリクエストを行っていると認識します。これを実行可能な攻撃にするために発生しなければならない重要なことがいくつかあります(これらの失敗のいずれかが原因で攻撃が失敗します)(これらは、それを防ぐ方法を理解するための重要なものです):
- アリスは、銀行が彼女を覚えているように、銀行のサイトにログインしている必要があります。これは、Cookie(「rememberme」)またはセッションを介して発生する可能性があります。ただし、彼女がブラウザを閉じたり(セッションを終了したり)、Cookieをクリアした場合、銀行のサイトは彼女を認識せず、リクエストを拒否するため、脅威はありません。
- ボブはリクエストに必要なすべてのパラメータを提供できる必要があります。そうしないと、銀行のウェブサイトがリクエストを拒否します。
ステートレスプロトコル(HTTP)に加えて「状態」の概念を提供するために、(1)のリスクを回避することはできません。常に「ログアウト」をクリックしたり、ウィンドウを閉じたりしない限り、ブラウザやセッションに情報を保存することはできません。ただし、(2)が問題になるのを防ぐことができます。これに対する私の解決策(そして他にもたくさんあると確信しています)は、あなたがしているようにハッシュを生成し、それをセッションに保存することです。
たとえば、
$_SESSION['token'] = md5(rand());
次に、そのトークンをすべての内部リンクに追加します。
http://www.mysite.com/secure.php?token=giuwnrefviunslfghahgliuwnvwrgbaasd
あなたは決して そのトークンをブラウザのメモリに保存します。つまり、Cookieです。リクエストが行われると、何かをする前に、トークンをチェックします
//note, you'll want to sanitize user input, I'm just being brief
if ($_GET['token'] != $_SESSION['token']){
//User either attempted to enter a link on their own or it's a CSRF attack
header('HTTP/1.1 403 Forbidden');
}else{
//do whatever needs to be done
}
これの鍵は、サイト上のすべてのリンクにトークンが含まれることです。ただし、ボブはそのトークンがブラウザのCookieに保存されていないため、そのトークンが何であるかを知る方法がありません。彼があなたのページの1つへのリンクを作成しようとすると、間違ったキーが含まれるか、キーが含まれず、拒否することができます。 (公平を期すために、彼は自分のコードを表示した特定のユーザーのトークンを正しく推測できる可能性がありますが、おそらく炎上する可能性が高くなります。)
トークンにタイムアウトを割り当てる必要はありません。ブラウザを閉じるとトークンが消去され、ユーザーがサイトにアクセスしたときにトークンを再生成する必要があるためです。