6-1 フォームとURLからの攻撃と防護策 [PHPセキュリティー]
フォームとURL
セマンティックURL攻撃
- セマンティックURL攻撃とはユーザーが直接URLを変更すること
セマンティックURL攻撃とは、ユーザーが直接URLを変更することです。
例えば、
1 | https://wepicks.net/member.php?user=suzuki |
とURLがなっている場合、suzuki の値を変更すれば他の結果が得られるかもしれないと値を変更することです。これがセマンティックURL攻撃となります。悪意がなくとも興味本位で値を変更する人もいるでしょう。
セマンティックURL攻撃が成功すると、URLの値を変更することによって、アプリケーションで意図しない情報が流出してしまいます。
URLはPHPにとって入力であり、フィルタの対象であるとフィルタリングの項で説明しましたが、入力に対してしっかりとフィルタを行えば、セマンティックURL攻撃を知らなくとも、アプリケーションをこのような攻撃から防ぐことが出来ます。
フォームとセマンティックURL攻撃の例
(1)
例は、「ユーザーがパスワードを忘れた場合に、ユニークな質問に答えてもらい、質問照合後、指定したメールアドレス宛にリセットしたパスワードを送る」という仕組みにおけるセマンティックURL攻撃に対する脆弱性です。
照合のためユーザーにユニークな質問に答えてもらい、照合が完了した場合、次回から使用する新しい電子メールアドレスを入力してもらいます。そして、そのアドレスへ新たなリセットされたパスワードを送ります。
(2) question.php
question.php 最初のユニークな質問の答えを要求するフォーム。
仮にユーザー名を suzuki とします。
- html
- ブラウザ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="utf-8"> <title>フォームとURLからの攻撃と防護策</title> </head> <body> <h1>ユニークな質問の答えを要求するフォーム</h1> <h2>question.php</h2> <form action="mailinput.php" method="GET"> ■ユーザー名を入力してください。<br> <input type="text" name="user" value="suzuki"><br> ■質問の答え 質問・・・・・・・?<br> <input type="text" name="question" value="answer"><br> <br> <input type="submit" value="照合">です。 </form> </body> </html> |
(3) mailinput.php
mailinput.php 照合後、リセットパスワードを送信するメールアドレスを入力するフォームです。
仮にメールアドレスを suzuki@mail.com とします。
- html
- ブラウザ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="utf-8"> <title>フォームとURLからの攻撃と防護策</title> </head> <body> <h1>リセットパスワードを送信するメールアドレスを入力するフォーム</h1> <h2>mailinput.php</h2> <h2>照合完了</h2> <form action="reset.php" method="GET"> <!-- 照合に答えたユーザー名 --> <input type="hidden" name="user" value="suzuki"> ■リセットパスワードを送信する電子メールを入力して下さい。<br> <input type="text" name="mail" value="suzuki@mail.com"><br> <input type="submit" value="次へ"> </form> </body> </html> |
(4) reset.php
reset.php ユーザー名と質問の照合 → メール入力後 → reset.php でパスワードをリセットして、新しい電子メール宛にリセットパスワードを送信します。
ここでは、必要な情報(パスワードをリセットするユーザー名と送り先のメールアドレス)をすべて持っています。ユーザーのユニークな質問を照合しているので、このフォームにたどり着いた場合、そのユーザーは偽者でないと認められます。
mailinput.phpフォームをサブミットした後、reset.phpに遷移すると次のURLに到達します。
1 | ・・・・・/reset.php?user=suzuki&mail=suzuki%40mail.com |
- html
- ブラウザ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="utf-8"> <title>フォームとURLからの攻撃と防護策</title> </head> <body> <?php //htmlエスケープ $user = htmlentities($_GET['user'], ENT_QUOTES, 'UTF-8'); $mail = htmlentities($_GET['mail'], ENT_QUOTES, 'UTF-8'); ?> <h1>新しい電子メール宛にリセットパスワードを送信</h1> <h2>reset.php</h2> <form action="reset.php" method="GET"> ■ユーザー名<br> suzuki<br> <input type="hidden" name="user" value="suzuki"> ■メールアドレス<br> suzuki@mail.com<br> <input type="hidden" name="mail" value="suzuki@mail.com"> <br> <input type="submit" value="リセット"> </form> </body> </html> |
(5) URLの攻撃の脆弱性
ユーザーは試しに次のURLを入力します。 user=の値を変更する
1 | ・・・・・/reset.php?user=yamada&mail=suzuki%40mail.com |
ユーザー yamada が存在する場合は、yamadaアカウントのための新しいパスワードが生成されてsuzuki@mail.comへ送られ suzuki が yamada アカウントを盗むことになります。
(6) 脆弱性の回避
脆弱性の回避
このような脆弱性を回避するために、SESSION変数を使用してフォームを追跡し、reset.phpが最後まで読み込まれたら、URLを変更して再リクエストできないようにさせたりすることで、アプリケーションの脆弱性を回避しましょう。
(7) 回避の例
回避の例
例えば、最初の質問入力フォーム question.php で
1 | $_SESSION['form'] = 'start'; |
とSESSION変数に値を格納します。
そして、最後の reset.php で
1 2 3 4 5 6 7 8 9 | <?php if($_SESSION['form'] === 'start'){ //処理開始 }else{ //不正な処理です } //reset.phpファイルを最後まで読み込んだらSESSION変数にendの値を入力する $_SESSION['form'] = 'end'; ?> |
こうすることで、URLを変更して再リクエストできないようにします。これは1つの例です。
セマンティックURL攻撃の防御策
- URLの値をフィルタリングする
- フォームを追跡する
セマンティックURL攻撃を防ぐには、URLの値を監視して、適切にフィルタリングすることです。
セマンティックURL攻撃はアプリケーションがURLの値をチェックしないで処理を実行する結果発生します。URLの値をしっかりフィルタして、意図しない値が送信された場合に情報が流出しないよう常に追跡しましょう。
また、フォームの最初から最後までをしっかり追跡し、ユーザーからの再リクエストなど、アプリケーションが意図しない操作を回避しましょう。
クロスサイトスクリプト攻撃(XSS)
- クロスサイトスクリプトは入力の表示(出力)による攻撃
- 攻撃者は悪意のある HTML や JavaScript を入力値に含めてページに埋め込む
- httpクライアントへの表示(出力)は必ずhtmlentities()関数を使用
- 入力のフィルタを出力のエスケープで回避できる
クロスサイトスクリプティングは、入力値に HTML や JavaScript などが記述されている場合に、適切なエスケープをしないで表示(出力)してしまうことで発生します。攻撃者は、入力値に悪意のあるJavaScriptなどを記述し、アプリケーションのページ内にコードを埋め込みます。その結果、コードを埋め込まれたページを表示した他のユーザーのセッションIDを盗んだり、他のサーバーへ攻撃をさせたりします。
クロスサイトスクリプト攻撃に対する脆弱性は入力を適切にエスケープしないで出力した際に発生します。これは、入力を適切にフィルタし、出力を適切にエスケープすることで回避することが出来ます。
httpクライアント(ユーザー)への出力は必ず htmlentities()関数 を使用してエスケープしましょう。
例えば以下の入力項目に対してユーザーが「<a href="https://wepicks.net" target="_blank">URL</a>」と入力します。
1 2 3 4 5 | <form> username: <input type="text" size="30" name="username"> <input type="submit" value="確認"> </form> |
これを確認画面でそのまま表示させると
となります。確認画面では意図しないURLが表示されることになります。
これをエスケープ処理して表示させるとHTMLは無効化されて文字列のみ表示されます。
エスケープ処理
1 | <?php echo htmlentities('<a href="https://wepicks.net" target="_blank">URL</a>', ENT_QUOTES, 'UTF-8'); ?> |
表示
ソースコードを見ると
1 | <a href="https://wepicks.net" target="_blank">URL</a> |
となっています。
この例では、攻撃とはなりませんが、ページにコードを埋め込まれエスケープせずに表示する危険性を表しています。例えば、掲示板などを考えてみましょう。運営者が入力された投稿文をエスケープせずに表示させていたとしましょう。そこへ悪意のある攻撃者が他のサーバーへ攻撃を仕掛ける危険なJavaScriptコードを投稿したとします。そのコードを含んだ投稿内容がエスケープされずに表示されていた場合、その掲示板を訪れたユーザーは、知らず知らずに他のサーバーを攻撃することになります。
クロスサイトスクリプト攻撃(XSS)の防御策
クロスサイトリクエストフォージェリ(CSRF)
- クロスサイトリクエストフォージェリはHTTPリクエストを捏造する攻撃方法
攻撃者が他のユーザーからのHTTPリクエストを捏造する攻撃方法です。攻撃者によって捏造されたHTTPリクエストが攻撃者からでなく、他の犠牲者から送信され、犠牲者は意図しない処理を実行させられます。具体例として、掲示板に意図しない書き込みをさせられたり、オンラインショップで買い物をさせられたりなどの被害が起こります。
攻撃の例
①ユーザーが商品を購入できるフォーム
1 2 3 4 5 6 7 8 9 | <form action="buy.php" method="POST"> アイテム: <select name="item"> <option name="pen">ペン</option> <option name="pencil">ペンシル</option> </select><br> 数量:<input type="text" name="quantity" size="2"><br> <input type="submit" value="購入"> </form> |
②攻撃者がフォームの要素を確認
攻撃者のフォームの要素がアイテム(item)とその個数(quantity)であることを知ります。
また、アイテムに期待される値が pen と pencil であることを知ります。buy.phpはこの情報を処理することが分かります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php if(isset($_REQUEST['item']) && isset($_REQUEST['quantity'])){ //フィルタ $clean = array(); $clean['item'] = $_REQUEST['item']; $clean['quantity'] = $_REQUEST['quantity']; //購入処理 if(BuyItem($clean['item'], $clean['quantity'])){ echo 'ご購入ありがとうございます。'; } //失敗 else{ echo '購入できませんでした。'; } } ?> |
③攻撃者が振る舞いを確認
攻撃者は振る舞いを知るためフォームを使用する。GETデータを使用して同じ動作をするか試します。
1 | https://wepicks.net/buy.php?item=pen&quantity=1 |
これが成功した場合、攻撃者は認証ユーザーとして訪れた場合のアイテムの購入を行う際のURLのフォーマットを知ることになります。
攻撃者が犠牲者にこのURLを仕向けるだけで攻撃が成立します。URLを画像に埋め込み、犠牲者にクリックさせるよう仕向ける等して、CSRF攻撃を成立させます。
1 | <a href="https://wepicks.net/buy.php?item=pen&quantity=1"><img src="./images/funny.gif"></a> |
クロスサイトリクエストフォージェリ(CSRF)の防御策
- 独自フォームの使用を強制する
- 入力フォームにワンタイムトークンを使用する
- htmlフォームではPOSTを使用する
このような攻撃を防ぐには、フォームにワンタイムトークンを含め、アプリケーションのフォームの使用を強制することが防護策となります。htmlフォームにはGETの替わりにPOSTを使用することでも攻撃を軽減できるでしょう。例えば、掲示板であれば、投稿者が掲示板に書き込む際、掲示板自身の入力フォームから投稿させるように強制することです。自身のフォーム以外からの値を受け入れてはいけません。
1 2 3 4 5 6 7 8 9 10 11 12 | <?php //無作為な文字列を使用してトークンを作成する。 $token = md5(uniqid(rand(), TRUE)); $_SESSION['token'] = $token; print " <form action='security2.php' method='POST'> <input type='text' name='username' size='20'> <input type='hidden' name='token' value='".$token."'> <input type='submit' value='送信'> </form> "; ?> |
↓
security2.php
1 2 3 4 5 6 7 | <?php if(isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token']){ print $_POST['username'].":有効なトークンです。"; }else{ print "無効なトークンです。"; } ?> |
タグ(=記事関連ワード)
日付
最終更新日:2017年08月09日