290 likes | 610 Views
HTML5 and Security Part 2: Open redirect and CSRF HTML5 セキュリティ その 2 : オープン リダイレクト 、 CSRF. Nov 14 2013 Yosuke HASEGAWA. # owaspjapan. 自己紹介. はせがわようすけ ネットエージェント株式会社 株式会社セキュアスカイ・テクノロジー 技術顧問 Microsoft MVP for Consumer Security Oct 2005 - http://utf-8.jp/. お知らせ announcement.
E N D
HTML5 and SecurityPart 2: Open redirect and CSRFHTML5セキュリティ その2 : オープンリダイレクト、CSRF Nov 14 2013 Yosuke HASEGAWA #owaspjapan
自己紹介 はせがわようすけ • ネットエージェント株式会社 • 株式会社セキュアスカイ・テクノロジー 技術顧問 • Microsoft MVP for Consumer Security Oct 2005 - • http://utf-8.jp/
Open redirect オープンリダイレクト • 本来はWebサイト内でのリダイレクト機能 • 攻撃者の指定した任意のサイトへジャンプできてしまう • フィッシングやSEOポイゾニングに使用される • サイト自体に被害を与えるわけではない • サイトの信頼は損ねる http://example.jp/go?url=/next/page.html http://example.jp/go?url=http://evil.example.com/
Open redirect オープンリダイレクト • 実在した例 site:www.microsoft.com/japan/ adult
Open redirect オープンリダイレクト • リダイレクトの方法 • HTTP応答として301または302を返す • JavaScriptによるlocationオブジェクトへの代入 • <meta refresh>
Redirect with 301 or 302 • 脆弱な例 • オープンリダイレクトだけでなくHTTPヘッダインジェクションもある。 #!/usr/bin/perl use URI::Escape; my $url = uri_unescape( $ENV{QUERY_STRING} || '/' ); print "Status: 302 Found\n"; print "Location: $url\n\n"; HTTP/1.1 302 Found Date: Tue, 28 Feb 2013 12:34:56 GMT Location: http://other.example.jp/
location with JavaScript • JavaScriptによるリダイレクト • JavaScriptコード増に伴い増加 • オープンリダイレクトだけでなくXSSにもhttp://example.jp/#javascript:alert(1) // http://example.jp/#/nextpage varurl=decodeURIComponent( location.hash.substring(1) ); location.href = url;
<meta refresh> • IE6,7の<meta refresh>は癖がある • 「;」より後ろのURLが転送先に使用される • 「;」をエスケープしても防げない • <meta refresh>によるリダイレクトの動的生成は避けたほうがよい <meta http-equiv="refresh" content="0;url=http://good/;url=http://evil/"> <meta http-equiv="refresh" content="0;url=http://good/;url=http://evil/">
オープンリダイレクトを防ぐために • 転送先URLの確認…実は難しいよね • http://example.com/ • //example.com/ • http:\\example.com/ • http:/\example.com • /\example.com/ • その他にもいろいろ if( url.match( /^\/[^\/]/ ) ){ location.href= url; } // bad code
オープンリダイレクトを防ぐために • HTTPレスポンスヘッダの改行コード • ブラウザによっては\r、\nどちらかだけでも改行とみなされる X-header: foo(0x0D 0x0A)Location: http://example.com/ X-header: foo(0x0D)Location: http://example.com/ X-header: foo(0x0A)Location: http://example.com/
オープンリダイレクトを防ぐために • 根本的対策 • 転送先URLを事前にリストとして保持 #!/usr/bin/perl use URI::Escape; my $index = uri_unescape( $ENV{QUERY_STRING} || '' ); my $pages = { foo=>'/foo', bar=>'/bar', baz=>'/baz' }; my $url = $pages->{$index} || '/'; print "Status: 302 Found\n"; print "Location: $url\n\n"; // JavaScriptによるリダイレクト varpages = { foo:'/foo', bar:'/bar', baz:'/baz' }; varurl = pages[ location.hash.substring(1) ] || '/'; location.href = url;
CSRF • XHR Lv.2により攻撃しやすくなった • 攻撃対象 : ファイルのアップロードフォーム <form method="POST" action="upload" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit"> </form>
CSRF • 従来の攻撃手法 • 罠ページではformを自動でsubmitする • これではファイルの中身は送信できない <body onload="document.forms[0].submit();"> <form method="POST" action="http://target.example.jp/upload" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit"> </form> </body>
CSRF • XHRLv.2によるCSRF攻撃 varxhr = new XMLHttpRequest(); var boundary = '----boundary'; var file="abcd"; //送信するファイルの内容 var request; xhr.open( 'POST', 'http://target.example.jp/upload', 'true' ); xhr.setRequestHeader( 'Content-Type', 'multipart/form-data; boundary=' + boundary ); xhr.withCredentials = true; // Cookieを付与 xhr.onreadystatechange = function(){}; request = '--' + boundary + '\r\n' + 'Content-Disposition: form-data; name="file"; ' + ' filename="filename.txt"\r\n' + 'Content-Type: application/octet-stream\r\n\r\n' + file + '\r\n' + '--' + boundary + '--'; xhr.send( request );
CSRF • XHR Lv.2によるCSRF攻撃 • XHRではクロスオリジンでリクエストを発行可能(サーバ側が非対応でも送信は可能) • Content-Typeおよび送信内容をJavaScriptで組み立てて発行(バイナリも可) • 従来不可能だったファイルのアップロードのCSRFが攻略可能になった
CSRF • 対策 • 従来同様、副作用を持つ全ての箇所にトークンを要求する <form method="POST" action="upload" enctype="multipart/form-data"> <input type="file" name="file"> <input type="hidden" name="token" value="2ACE730295E23F2C"> <input type="submit"> </form>
HTML5時代のCSRF対策 • XMLHttpRequestを明示するリクエストヘッダを付与(これだけ!!) xhr= new XMLHttpRequest(); xhr.open( "POST", "/inquiry", true ); xhr.setRequestHeader( "Content-Type", "..." ); xhr.setRequestHeader( "X-Requested-With","XMLHttpRequest"); xhr.send( params ); POST http://example.jp/inquiry HTTP/1.1 Host: example.jp UserAgent: Mozilla/5.0X-Requested-With: XMLHttpRequest Content-Type: application/x-www-form-urlencoded
HTML5時代のCSRF対策 • 罠サイトからの<form>によるPOSTではX-Requested-Withリクエストヘッダは付与されない <body onload="javascript:forms[0].submit()"> <form method="POST" action="http://example.jp/inquiry"> <input type="hidden" value="..."> </form> POST http://example.jp/inquiry HTTP/1.1 Host: example.jp UserAgent: Mozilla/5.0 Referer: http://trap.example.com/ Content-Type: application/x-www-form-urlencoded
HTML5時代のCSRF対策 • 罠サイトからのXHRによるPOSTでは罠サイトを指すOriginヘッダを持つPreflightリクエストが発行される xhr= new XMLHttpRequest(); xhr.open( "POST", "http:/example.jp/inquiry", true ); xhr.setRequestHeader( "Content-Type", "..." ); xhr.setRequestHeader( "X-Requested-With","XMLHttpRequest"); xhr.send( params ); OPTIONS /inquiry HTTP/1.1 Host: example.jp UserAgent: Mozilla/5.0 Origin: http://trap.example.comAccess-Control-Request-Method: POST Access-Control-Request-Headers: X-Requested-With
HTML5時代のCSRF対策 • サーバ側でX-Requested-WithヘッダとOriginヘッダを確認することでCSRF対策が可能 • セッションの保持が不要 • クロスドメインPOSTでのCSRF対策も可能 • JavaScript必須 • <form>と違いページ遷移しない • DNS rebinding対策必須
まとめ • オープンリダイレクト • JSによるオープンリダイレクトが増加傾向 • 転送先URLを事前に固定リストで保持 • CSRF • JSによってファイルアップロードが可能 • XHRではセッションなしにCSRF対策可能
Question? 質問 hasegawa@utf-8.jp hasegawa@netagent.co.jp @hasegawayosuke http://utf-8.jp/