サーバー側の状態を必要とせず、タイムアウトを必要としないソリューションは、署名されたトークンです。フォームに含めるランダムな値を作成し、そのトークンに自分だけが知っている秘密で署名します。
$secret = 'weufiwu93tu2b248hg24';
$token = uniqid('', true);
$signature = sha1($secret . ':' . $token);
次に、トークンと署名をフォームに埋め込みます。フォームを再度受信したら、フォームからのトークンを使用して操作を繰り返し、SHA1(secret:token)
結果をフォームからの署名と比較します。適切に選択されたランダムな秘密と堅牢なハッシュがある場合、秘密を知っている人以外は誰もトークンに署名できないため、トークンがあなたからのものであることが証明されます。
さらに、トークンの有効性を制限するためにフォーム/署名にタイムスタンプを含めることができます (5 分より長くしますが、トークンを永久に使用できるほど長くはしません)。ユーザー ID は、トークンを特定のユーザー、フォームフィールドインジェクションから保護するために予想されるフォームフィールド、およびチェックしたいその他のもの。例えば:
signature = SHA1(secret:token:timestamp:userid:[form_field_name[:...]])
上記の署名の場合、署名、トークン、タイムスタンプ、および明らかにフォーム フィールドをフォームに埋め込みます。送信時に、送信されたタイムスタンプが特定のウィンドウ内にあることを確認し、サーバーからシークレットとユーザー ID を取得し、それらすべての部分で署名を再作成し、送信された署名と照合します。
上記のコードは単なる例であることに注意してください。トークンはランダム性のより良いソースを使用し、より長くする必要があり、ハッシュ関数は HMAC や bcrypt のようなより堅牢なものにする必要があります。これはアイデアを伝えるためのものであり、実装の詳細ではありません。
実際の実装はKunststube\CSRFPにあります。とにかくそのようなものが必要だったので、この質問に答えてこれをまとめました。