これなら合格! 正しいリダイレクターの作り方:HTML5時代の「新しいセキュリティ・エチケット」(4)(2/3 ページ)
えっ、まだmeta refreshとか301使ってるの? リダイレクターの作り方も時代とともに移り変わります。記事を読んだらすぐに使えるセキュリティ・エチケットを紹介しましょう。
リダイレクトの方法
Webアプリケーションにおいて、リダイレクトを実現するための方法は大きく以下の3種類があります。
- HTTPの応答としてステータス301または302を返す
- <meta refresh>によるリダイレクト
- JavaScriptによるlocationオブジェクトへの代入
以下、それぞれの方法によるリダイレクトとオープンリダイレクターとしての悪用について順に説明します。
1.HTTPの応答としてステータス301または302を返す
他のリソースへのリダイレクトを実現する方法としては、HTTPのステータスコードとして301または302を返し、リダイレクト先のURLをLocation:レスポンスヘッダーで示すという方法が最も広く使用されています。なお、ステータスコード301はリソースURLが恒久的に変更されていることを、302は一時的に変更されていることを意味しています。
GET http://example.jp/go?url=/next/page.html HTTP/1.1
Host: example.jp
HTTP/1.1 302 Found
Date: Mon, 09 Jun 2014 02:17:27 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 0
Location: /next/page.html
この場合、Location:レスポンスヘッダーで返されるURLにリダイレクトが行われます。もし攻撃者が自由にこのURLを指定できた場合、オープンリダイレクターとして悪用可能となります。
GET http://example.jp/go?url=http://evil.example.com/ HTTP/1.1
Host: example.jp
HTTP/1.1 302 Found
Date: Mon, 09 Jun 2014 02:17:27 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 0
Location: http://evil.example.com/
さらに、URL部分に改行文字を含めることができる場合、オープンリダイレクターだけではなく、HTTPヘッダーインジェクションの脆弱性も存在することになります。下記の例では、ヘッダーを挿入することでクッキーを不正に設定しています。
GET http://example.jp/go?url=/%0D%0ASet-Cookie%3A%20fakevalue=abcd HTTP/1.1
Host: example.jp
HTTP/1.1 302 Found
Date: Mon, 09 Jun 2014 02:17:27 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 0
Location: /
Set-Cookie: fakevalue=abcd
2.<meta refresh>によるリダイレクト
HTTPレスポンスヘッダーではなく、HTMLのmeta要素を使用してのリダイレクト、俗に言う「meta refresh」もよく使用されています。
meta要素によるリダイレクトでは、「http://example.jp/go?url=/next/page.html」にアクセスがあったとき、サーバーは以下のようにmeta要素のcontent属性の値を動的に生成したHTMLを応答します。
<meta http-equiv="Refresh" content=0;URL=/next/page.html">
攻撃者は、301または302応答によるオープンリダイレクターの場合同様、「http://example.jp/go?url=http://evil.example.com/」のようなURLへ被害者を誘導することで、以下のようなHTMLへアクセスさせ、攻撃者の用意したサイトへのリダイレクトを狙います。
<meta http-equiv="Refresh" content=0;URL=http://evil.example.com/">
オープンリダイレクターを防ぐために、content属性として生成されるURLを、常にhttp://example.jp/から始まる、絶対URLとして出力するという方法がとられることがあります。例えば、「http://example.jp/go?url=/next/page.html」へのアクセスでは、リダイレクト先URLに「http://example.jp」を付与し、次のようなHTMLを生成するというものです。
<meta http-equiv="Refresh" content=0;URL=http://example.jp/next/page.html">
一見、この方法で任意サイトへのリダイレクトは阻止できるかのように思えますが、実際にはこの方法ではオープンリダイレクターを完全に防ぐことはできません。Internet Explorer 7(以下、IE7)ではcontent属性に複数の「URL=」という指定がある場合に、最後に指定された「URL=」の部分がリダイレクト先として利用されるからです。
例えば、攻撃者は次のようなURLに被害者を誘導します。
http://example.jp/go?url=/;URL=http://evil.example.com/
このようなURLを与えられた場合に、以下のようなHTMLが生成されるとします。
<meta http-equiv="Refresh" content="0;URL=http://example.jp/;URL=http://evil.example.com/">
このHTMLをIE7で開いた場合、リダイレクト先としてはcontent属性に含まれる2つの「URL=」の後ろ側、「http://evil.example.com/」が使用され、攻撃者が指定したサイトへと誘導されることになります。
オープンリダイレクターではありませんが、リダイレクト先としてjavascriptスキームが含まれる場合、一部のブラウザーではそのページ上でJavaScriptが実行されてしまい、クロスサイトスクリプティング脆弱性となることもあります。
<meta http-equiv="Refresh" content="0;URL=javascript:alert(location.href)">
このように、meta要素のcontent属性を動的に生成してのリダイレクトは、さまざまな問題が発生しやすいため、<meta refresh>を使ったリダイレクト実装は避けるべきでしょう。
3.JavaScriptによるlocationオブジェクトへの代入
Webアプリケーションにおけるクライアント側への処理のシフトや、JavaScriptコード量の増加に伴い、JavaScript内でのlocationオブジェクトへの代入によって、リダイレクトを実装する機会も増加しています。
location.href = location.hash.substring(1);
例えば上記のようなコードが書かれたページに、「http://example.jp/#/next/page.html」のようなURLとしてアクセスすると、URL中の#より後ろの部分がリダイレクト先として利用されます。また、リダイレクト先のURL全体ではなく、機能名などをURLのフラグメント部分(#より後ろの部分)に指定するといったこともよく行われています。
// http://example.jp/#news location.href = "/" + location.hash.substring(1) + ".html";
このようなページでは、最初の例であれば攻撃者は「http://example.jp/#http://evil.example.com/」のようなURLへ被害者を誘導することで、「http://evil.example.com/」へ被害者をリダイレクトさせることができます。また、「http://example.jp/#javascript:alert(location.href)」などへ被害者を誘導することで、そのページ上でJavaScriptを実行させることができるクロスサイトスクリプティング脆弱性(DOM based XSS)ともなります。
2番目の例の場合でも、攻撃者は「http://example.jp/#/evil.example.com/?」のようなURLへ被害者を誘導することで、location.hrefには「//evil.example.com/?.html」が代入され、攻撃者の用意したサイトへ被害者をリダイレクトさせることができます。
Copyright © ITmedia, Inc. All Rights Reserved.