私のサイトでアクションがあります:
http://mysite.com/User/Logout
これにより、現在のユーザーがセッションからログアウトされます。これは単純なGETリクエストであるため、悪意のあるユーザーがこのページへのリンクを作成するか、このリンクを画像のsrc
属性に配置して、ユーザーを強制的にログアウトさせる可能性があります。ログアウトリンクのシンプルさを行き過ぎずに維持したいのですが、同時に上記のシナリオが発生しないようにしたいと思います。
何か案は?
私のサイトでアクションがあります:
http://mysite.com/User/Logout
これにより、現在のユーザーがセッションからログアウトされます。これは単純なGETリクエストであるため、悪意のあるユーザーがこのページへのリンクを作成するか、このリンクを画像のsrc
属性に配置して、ユーザーを強制的にログアウトさせる可能性があります。ログアウトリンクのシンプルさを行き過ぎずに維持したいのですが、同時に上記のシナリオが発生しないようにしたいと思います。
何か案は?
GET リクエストを使用してユーザーをログアウトさせる (または、GET リクエストを使用してそれよりも重要なことを行う) と、Web サイトはクロスサイト リクエスト フォージェリ攻撃に対して脆弱になります。ユーザーをログアウトするには、POST を使用する必要があります。GET はべき等アクション専用です。RFC 2616 セクション 9.1を参照してください。
この場合の GET の使用は RFC に準拠していませんが、XSRF を防ぐために変更する必要があるのはそれだけではないことに注意してください。優れた説明については、ircmaxell によるこの回答を参照してください。
CSRF 攻撃から保護するためにできるオプションがいくつかあります。
フォームとランダム トークンを使用します。したがって、「リンク」を使用する代わりに、セッションで設定されたランダムなトークンをフォームに使用します
<form action="/User/logout" method="post">
<submit name="logout" value="Logout" />
<input type="hidden" name="token" value="<?php echo getSessionToken(); ?>" />
</form>
このタイプのアクションには POST が最適ですが、あまり問題なくフォームを GET に変更できます。
次に、php で次のようにします。
if (getSessionToken(true) != $_POST['token']) {
die('CSRF!');
}
getSessionToken
次のように動作するはずです。
function getSessionToken($reset = false) {
if (!isset($_SESSION['random_token'])) {
$_SESSION['random_token'] = sha1(uniqid(mt_rand(), true));
}
$token = $_SESSION['random_token'];
if ($reset) {
unset($_SESSION['random_token']);
}
return $token;
}
また、トークンを取得してチェックするときはいつでも、トークンを新しいものにリセットする必要があることに注意してください (これはこれが行うことです)。これにより、攻撃者が送信時にトークンを検出し、値を再送信するリプレイ攻撃を防ぎます。
リンクを使用する必要がある場合は、リンクにトークンを埋め込みます。ただし、ユーザーがリンクをコピーして他の誰かに貼り付ける可能性があるため、これは攻撃を受けやすいことに注意してください。自己リセット トークンである限り、複数のタブを使用しても問題はありません。ただし、最適ではないことに注意してください。
<a href="/User/logout?token=<?php echo getSessionToken(); ?>">Logout</a>
何もないよりは絶対にましです。ただし、最善の保護のためにフォームを使用することをお勧めします。
CSRFを防止するために、 OWASP CSRF ガイドラインを読み、それに従うことを強くお勧めします。それはあなたが知る必要があることと、その理由を教えてくれます...
HTTP メソッドを変更せずに、一意の ID をユーザー セッションに追加し、それをログアウト リンクに追加できます。ログアウト アクションが実行され、2 つの ID が一致する場合、ログアウトは有効です。そうでなければ、そうではありません!
like/Logout?#NONCE# に書き換えます。#NONCE# はリクエストごとに変更する値です。
私はパーティーに遅れていると思いますが、これが私がそれを処理する方法です:
<?php
session_start();
function logoutButton($name = 'logout', $action = '/User/logout'){
$random_token = md5(uniq_id());
$_SESSION['csrf'] = $random_token;
$form = '<form ><input type="hidden" value="'. $random_token .'" name="' .$name. '"><input type="button" value="logout"><</form>';
return $form;
}
public static isValidRequest($name = 'logout'){
if(isset($_POST[$name]) && $_POST[$name] === $_SESSION['csrf']){
return true;
}
return false;
}
}
?>
ログアウトボタンを表示する
echo logoutButton();
ユーザーを安全にログアウトするには
if(isValidRequest()){
//logout
}
誰かの役に立てば幸いです。
編集:これは私が作成したクラスですhttps://github.com/sahithvibudhi/PHP-CSRF-Protection-class
ログアウト ページに何らかのバリデータを渡す必要があります。そして、それはセッションに特有で、推測するのが難しいものでなければなりません。さて、適切な値があればいいのですが...そうです、セッション識別子です。
セッション管理には Cookie を使用する必要があり、セッション Cookie に http only フラグを設定する必要があることに注意してください。そのため、PHP からリンクを設定する (またはセッション ID を JavaScript 読み取り可能な Cookie にコピーする) 必要があります。
<?php
session_start();
if ($_GET['logout_valid']!==session_id()) {
// handle invalid logout request
exit;
} else {
$_SESSION=array();
session_destroy();
}