クロスサイト リクエスト フォージェリ (CSRF) は、攻撃者が被害者を通じて任意の HTTP リクエストを送信できるようにする攻撃方法の一種です。ここでの被害者は無意識の共犯者であり、偽造された要求はすべて攻撃者ではなく彼から出ています。このように、どのリクエストがクロスサイト リクエスト フォージリ攻撃の対象となっているかを判断することは非常に困難です。実際、クロスサイト リクエスト フォージリ攻撃に対する予防策を講じないと、アプリケーションが脆弱になる可能性があります。
ユーザーがペンや鉛筆を購入できるシンプルなアプリを以下で見てみましょう。インターフェイスには次の形式が含まれています:
CODE:
<form action="buy.php" method="POST"> <p> Item: <select name="item"> <option name="pen">pen</option> <option name="pencil">pencil</option> </select><br /> Quantity: <input type="text" name="quantity" /><br /> <input type="submit" value="Buy" /> </p> </form>
攻撃者はまずアプリケーションを使用して、いくつかの基本情報を収集します。たとえば、攻撃者は最初にフォームにアクセスし、項目と数量という 2 つのフォーム要素を発見します。また、項目の値が鉛筆またはペンであることも知っています。
次の buy.php プログラムはフォーム送信情報を処理します:
CODE:
<?php session_start(); $clean = array(); if (isset($_REQUEST['item'] && isset($_REQUEST['quantity'])) { /* Filter Input ($_REQUEST['item'], $_REQUEST['quantity']) */ if (buy_item($clean['item'], $clean['quantity'])) { echo '<p>Thanks for your purchase.</p>'; } else { echo '<p>There was a problem with your order.</p>'; } } ?>
まずこのフォームを使用して観察します行動。たとえば、鉛筆を購入した後、攻撃者は、購入が成功すると感謝のメッセージが表示されることを知っています。これに気づいた攻撃者は、次の URL にアクセスして GET 経由でデータを送信することで、同じ目的が達成できるかどうかを確認しようとします。 http://www.php.cn/
成功した場合、攻撃者は正規のユーザーがアクセスしたときに購入をトリガーできる URL 形式を取得します。この場合、攻撃者は被害者を URL にアクセスさせるだけでよいため、クロスサイト リクエスト フォージェリ攻撃を実行するのは非常に簡単です。
クロスサイト リクエスト フォージェリ攻撃を開始する方法は数多くありますが、画像などの埋め込みリソースを使用するのが最も一般的です。この攻撃がどのように機能するかを理解するには、まずブラウザがこれらのリソースをどのように要求するかを理解する必要があります。
http://www.php.cn/ にアクセスすると (写真 2-1)、ブラウザはまずこの URL で識別されるリソースをリクエストします。このリクエストの戻り内容は、ページのソース ファイル (HTML) を表示することで確認できます。 Google ロゴ画像は、ブラウザーが返されたコンテンツを解析した後に見つかりました。この画像は HTML の img タグで表され、タグの src 属性が画像の URL を表します。次に、ブラウザは画像に対して別のリクエストを発行します。2 つのリクエストの唯一の違いは URL です。
図 2-1. Google のホームページ
CSRF 攻撃は、これを利用するために img タグを使用する可能性があります で特定された次の画像を含む Web サイトにアクセスすることを検討してください。 出典:
上記の原則に基づいて、クロスサイト リクエスト フォージェリ攻撃は img タグを通じて実行できます。訪問に以下が含まれるかどうかを検討してください。 次のソース コードを含むページはどうなりますか:
<img src="http://store.example.org/buy.php?item=pencil&quantity=50" />
buy.php スクリプトは $_POST の代わりに $_REQUEST を使用するため、store.example.org ストアにログインしているすべてのユーザーは、この URL をリクエストすることによって 50 本の鉛筆を購入することになります。
$_REQUEST が推奨されない理由の 1 つは、クロスサイト リクエスト フォージェリ攻撃の存在です。
完全な攻撃プロセスを図 2-2 に示します。
図 2-2. 画像によるクロスサイト リクエスト フォージェリ攻撃
画像をリクエストするとき、一部のブラウザはリクエスト ヘッダーの Accept 値を変更して、画像タイプに高い優先順位を与えます。これを防ぐには保護措置が必要です。
你需要用几个步骤来减轻跨站请求伪造攻击的风险。一般的步骤包括使用POST方式而不是使用GET来提交表单,在处理表单提交时使用$_POST而不是$_REQUEST,同时需要在重要操作时进行验证(越是方便,风险越大,你需要求得方便与风险之间的平衡)。
任何需要进行操作的表单都要使用POST方式。在RFC 2616(HTTP/1.1传送协议,译注)的9.1.1小节中有一段描述:
“特别需要指出的是,习惯上GET与HEAD方式不应该用于引发一个操作,而只是用于获取信息。这些方式应该被认为是‘安全’的。客户浏览器应以特殊的方式,如POST,PUT或DELETE方式来使用户意识到正在请求进行的操作可能是不安全的。”
最重要的一点是你要做到能强制使用你自己的表单进行提交。尽管用户提交的数据看起来象是你表单的提交结果,但如果用户并不是在最近调用的表单,这就比较可疑了。请看下面对前例应用更改后的代码:
CODE:
<?php session_start(); $token = md5(uniqid(rand(), TRUE)); $_SESSION['token'] = $token; $_SESSION['token_time'] = time(); ?> <form action="buy.php" method="POST"> <input type="hidden" name="token" value="<?php echo $token; ?>" /> <p> Item: <select name="item"> <option name="pen">pen</option> <option name="pencil">pencil</option> </select><br /> Quantity: <input type="text" name="quantity" /><br /> <input type="submit" value="Buy" /> </p> </form>
通过这些简单的修改,一个跨站请求伪造攻击就必须包括一个合法的验证码以完全模仿表单提交。由于验证码的保存在用户的session中的,攻击者必须对每个受害者使用不同的验证码。这样就有效的限制了对一个用户的任何攻击,它要求攻击者获取另外一个用户的合法验证码。使用你自己的验证码来伪造另外一个用户的请求是无效的。
该验证码可以简单地通过一个条件表达式来进行检查:
CODE:
<?php if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token']) { /* Valid Token */ } ?>
你还能对验证码加上一个有效时间限制,如5分钟:
CODE:
<?php $token_age = time() - $_SESSION['token_time']; if ($token_age <= 300) { /* Less than five minutes has passed. */ } ?>
通过在你的表单中包括验证码,你事实上已经消除了跨站请求伪造攻击的风险。可以在任何需要执行操作的任何表单中使用这个流程。
尽管我使用img标签描述了攻击方法,但跨站请求伪造攻击只是一个总称,它是指所有攻击者通过伪造他人的HTTP请求进行攻击的类型。已知的攻击方法同时包括对GET和POST的攻击,所以不要认为只要严格地只使用POST方式就行了。
以上就是PHP安全-跨站请求伪造的内容,更多相关内容请关注PHP中文网(www.php.cn)!