[PR]小規模ECサイトに最適なWAF、SiteGuard Lite
徳丸浩の日記
2009年03月11日 文字コードのセキュリティ問題はどう対策すべきか
_U+00A5を用いたXSSの可能性
前回の日記では、昨年のBlack Hat Japanにおける長谷川陽介氏の講演に「趣味と実益の文字コード攻撃(講演資料)」に刺激される形で、Unicodeの円記号U+00A5によるSQLインジェクションの可能性について指摘した。
はせがわ氏の元資料ではパストラバーサルの可能性を指摘しておられるので、残る脆弱性パターンとしてクロスサイト・スクリプティング(XSS)の可能性があるかどうかがずっと気になっていた。独自の調査により、XSS攻撃の起点となる「<」や「"」、「'」などについて「多対一の変換」がされる文字を探してきたが、現実的なWebアプリケーションで出現しそうな組み合わせは見つけられていない。
一方、U+00A5が処理系によっては0x5C「\」に変換されることに起因してXSSが発生する可能性はある。JavaScriptがからむ場合がそれだ。しかし、実際にXSS脆弱性が発生するには、次のような状況を想定する必要がある。
- 入力(HTTPリクエスト)はUnicodeで受け取る
- 内部の処理もUnicodeで行われる
- 出力(HTTPレスポンス)のエンコーディングはShift_JISあるいはEUC-JP
すなわち、入力(リクエスト)と出力(レスポンス)で異なる文字エンコーディングを想定しなければならない。これ自体は現実性が薄い。
この問題については、既に佐名木氏らの研究がある。佐名木氏は、Apache Tomcatに着目して以下のように記述している。
実験のポイントは、Tomcat の仕様変更である。Tomcat4 系からTomcat5 系へのバージョンアップによって、クエリー文字列は常にUTF-8 として受け取るように仕様が変更された。
この仕様変更に着目することで、ANSI の世界でデータ処理、そしてデータ出力を行っているJavaServlet に対してUTF-8 の世界の文字を与えることができる。
[Unicodeとサニタイジング回避テクニック ver1.6より引用]
Tomcatのクエリ文字列の文字化け問題はFAQであって、現実には「常にUTF-8として」受け取られるわけではなく、server.xmlの設定により、useBodyEncodingForURI="true" (クエリ文字列の文字エンコーディングをPOSTのエンコーディングと一致させる)を指定することができる。従って、佐名木氏の指摘しておられる状況もなくはないだろうが、もう少し現実的に *ありそうな* 可能性を検討したい。
そこで私は、HTTPリクエストの文字エンコーディングを「自動認識」させている場合に注目して調査を行った。各処理系に対する考察を以下に述べる。
Javaの場合
Javaは前述のように、U+00A5が\x5Cに変換されるので有力な候補だが、J2SEの文字エンコーディング自動判定機能は、JIS系の文字エンコーディングの範囲で行われる(JISAutoDetect)ため、上記の条件を満たすことができない。文字エンコーディングの自動判定を自作することは可能だが、検討の対象からは外すことにした。
PHPの場合
PHPは文字エンコーディングの自動判定が柔軟だが、一方、U+00A5が全角の円記号「¥」に変換されるため、XSSには利用できない。
Perlの場合
PerlにはJcode.pmやEncode.pmに文字エンコーディングの自動判定機能がある。しかし、UnicodeからShift_JISなどへの変換に際してU+00A5が「?」に変換されるため、やはりXSSには利用できない…と思っていた。最近までは。
しかし、私がITproに連載している連載中の記事「第6回■異なる文字集合への変換がぜい弱性につながる 」に対して、id:nihenさんからブックマークコメントを頂戴した。
【Perl(Encode.pm).(略).では発生しない】cp932では発生するです。http://cpansearch.perl.org/src/DANKOGAI/Encode-2.31/ucm/cp932.ucm
すなわち、UTF-8からShift_JISへの変換だとU+00A5は「?」に変換されるが、cp932(Windowsの機種依存文字を考慮したShift_JIS)への変換の場合は「\」(\x5C)に変換されるというのだ。確認したところ、たしかにそうなる。これで、U+00A5によるXSSの可能性が出てきた。さっそく試してみよう。
以下にサンプルコードを示す。
#!/usr/bin/perl use CGI; use utf8; use Encode; use Encode::Guess qw/utf8 shiftjis euc-jp/; my $query = CGI->new; my $p = decode 'Guess', $query->param('p'); # 制御文字のチェック…省略 # 次の行はJavaScript文字列リテラルのエスケープ $p =~ s/(?=[\\\'\"])/\\/g; # \ → \\ ' → \' " → \" $p = $query->escapeHTML($p); # HTMLエスケープ print encode 'cp932', <<EOT; Content-Type: text/html; charset=Shift_JIS <html> <body onload="alert('$p');"> テスト </body></html> EOT
この簡単なスクリプトは、クエリストリングpの値をalertダイアログに表示するだけの簡単なものだ。処理の流れは以下のようになる。
- 文字エンコーディングの自動判定候補として、UTF-8、Shift_JIS、EUC-JPを指定
- クエリストリングpを読み込み、文字エンコーディング自動判定でUTF-8に変換
- JavaScript文字列リテラルとしてのエスケープ
- HTMLエスケープ
- 文字エンコーディングcp932を指定してHTML生成
- body要素のonloadイベントハンドラにalert関数を生成
JavaScriptの動的生成に対して必要なエスケープ処理については、過去にXSS対策:JavaScriptのエスケープ(その2)などで説明した通りである。
私はそもそもJavaScriptの動的生成を推奨していないが、イベントハンドラにJavaScriptを置く場合は比較的シンプルに考えられる。上記のように、JavaScriptとしてのエスケープとHTMLのエスケープを2段階で行えばよい。面倒ではあるが、SCRIPT要素に置く場合のようにデータの途中に</SCRIPT>が出てくるような特殊ケースは考えなくて良い。
このスクリプトに対して、以下のような入力を与える(U+00A5は赤色全角の円記号¥で記述)。
a¥');alert(document.cookie);//
この文字列は以下のように処理される。まずJavaScriptのエスケープ処理(' → \')。
a¥\');alert(document.cookie);//
次にHTMLエスケープ(' → ')
a¥\');alert(document.cookie);//
そしてcp932に変換(¥ → \)
a\\');alert(document.cookie);//この文字列はJavaScriptの実行に際して、HTMLデコードされ以下のようになる。
alert('a\'');alert(document.cookie);//');"
すなわち、JavaScriptの文字列リテラルが突破され、第二のalertが追加された。XSSの成功である。
対策
この問題の根本原因は、UTF-8→cp932(Shift_JIS)の変換に伴う多対一変換にある。従って、文字エンコーディングを全てUTF-8に統一することで根本対策となる。しかし、一般的には、携帯電話や電子メールなど、JIS系文字集合を使わざるを得ない場合もあり、ブラウザとのやりとりはShift_JIS(あるいはEUC-JP)、プログラム内部ではUTF-16やUTF-8というケースは多いだろう。
このような場合は、プログラムの実行環境はUnicodeだが、処理対象となる文字集合をJIS系文字集合(マイクロソフト標準キャラクタセットなど)に限定することで対策が可能だ。具体的には、入力時の文字エンコーディング自動判定をやめ、エンコーディングを明示することだ。だが、もっとよい方法があるかもしれない。
一つの可能性として、長谷川氏の講演資料に指摘されているような「検査後には変換しない」すなわち、変換してから検査(エスケープ)する方法もある。しかし、PerlはShift_JISの文字列処理には対応していないので、cp932(Shift_JIS)に変換してからのエスケープも容易ではない。
また、「もっとよい方法」とは、従来言われてきた「過剰エスケープ」を指すわけではない。上記の例で言えば、スラッシュ「/」を「\/」にエスケープすれば、JavaScriptのコメント「//」が有効でなくなり、JavaScriptの実行エラーになるので攻撃は成立しない。しかし、そのような対策はアドホックで、理論的な裏付けに乏しいものだ。
また、今回は取り扱わないが、文字エンコーディングを利用した攻撃についても同様のことが言える。PerlのEncode::decodeは文字エンコーディングのチェックを行うので、そもそも不正な文字エンコーディングについては除去してくれる。エラーにしたければ(そうするべきだが)、オプションの第3パラメータCHECKにEncode::FB_CROAKを指定すればよい。それでも残る問題は処理系のバグ(脆弱性)なのだ。処理系のバグに対してアプリケーション側で対策しなければならない場合もあるだろうが、それは原因の所在を明確にした上での話だ。
文字コードのセキュリティ問題に関しては、公開されている情報が非常に少ない。とくに文字集合をアプリケーション開発の際にどのように取り組むべきかという議論はほとんどなされていないように思う。私は、ITproの連載の中で私見を述べているが、先行する研究がほとんどないので原理から手探りで検討している状態だ。この問題に対する活発な議論が行われることを期待する。
- https://www.google.co.jp/ ×1040
- https://www.google.com/ ×29
- http://ledyba.org/2011/12/04104017.php ×16
- http://www.tokumaru.org/ ×12
- http://www5d.biglobe.ne.jp/~noocyte/Programming/Ch... ×10
- https://search.yahoo.co.jp/ ×4
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×3
- https://www.bing.com/ ×3
- https://www.google.com/search?q=サニタイジング ×2
- https://www.google.com.vn/ ×2
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×2
- https://www.google.co.in/ ×2
- http://www.moreslowly.jp/bm/?tags=unicode security... ×2
- http://sp-search.auone.jp/search?q=unicode U+00A5 ... ×2
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.nl/ ×1
- https://www.google.de/ ×1
- https://www.google.co.kr/ ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.ru/ ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- https://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&... ×1
- http://yandex.ru/clck/jsredir?from=yandex.ru;searc... ×1
- http://yandex.ru/clck/jsredir?from=yandex.ru;searc... ×1
- http://yandex.ru/clck/jsredir?from=yandex.ru;searc... ×1
- http://www.tokumaru.org/d/20090311.html ×1
- http://www.moreslowly.jp/bm/?tags=XSS ×1
- http://www.moreslowly.jp/bm/?tags=Security ×1
- http://search.smt.docomo.ne.jp/result?search_box=h... ×1
- http://search.fenrir-inc.com/?q=pdo quote セキュリティ&h... ×1
- http://search.fenrir-inc.com/?q=java 00a5&hl=ja&sa... ×1
- http://search.fenrir-inc.com/?q=charset=cp932 tomc... ×1
- http://search.fenrir-inc.com/?q=XMLHttpRequest EUC... ×1
- http://search.fenrir-inc.com/?q=文字コード クロスサイトスクリプティ... ×1
- http://search.fenrir-inc.com/?hl=ja&channel=sleipn... ×1
- http://search.fenrir-inc.com/?hl=ja&channel=sleipn... ×1
- http://search.fenrir-inc.com/?hl=ja&channel=sleipn... ×1
- http://search.fenrir-inc.com/?hl=ja&channel=sleipn... ×1
- http://ledyba.org/page/6 ×1
- http://ledyba.org/category/book ×1
- http://kjunichi.cocolog-nifty.com/misc/ ×1
- XSS 変換 コード ×3 / XSS 文字 utf-8 ×2 / alert javascript エスケープ ×2 / セキュリティ エンコーディングによる攻撃 ×2 / Shift_JIS uft-8 脆弱性 ×1 / shift-jis xss ×1 / php サニタイジング 円記号 ×1 / javascript 文字コード 脆弱性 回避 ×1 / javascript エスケープ 対策 ×1 / java セキュリティ > 文字コード ×1 / XSS 文字コード <> ×1 / Unicode U+00A5 セキュリティ ×1 / U+00A5 UTF-8 ×1 / U+00A5によるXSS ×1 / TOMCAT クエリ 攻撃 セキュリティ ×1 / 文字コード 脆弱性 ×1 / PHP 全角変換 XSS ×1 / PHP 文字コード 攻撃 UTF-8 ×1 / 文字コード XSS ×1 / クエリ文字列 "UTF-8" ×1 / 文字コード xss ×1 / 文字コード XSS 徳丸 ×1 / リスト Unicode 脆弱性 ×1 / クロスサイトスクリプティング 文字コード ×1 / U+00A5 ×1 / PHP 00A5 ×1 / javascript 文字コード ansi ×1 / XSS unicode ×1 / Unicodeエスケープを利用したクロスサイトスクリプティング ×1 / 文字コード指定 不備 ×1
[PR]小規模ECサイトに最適なWAF、SiteGuard Lite
HASHコンサルティング株式会社
最近の記事
- 2011年08月30日
- 1. RSSフィードをリダイレクトします
- 2011年07月01日
- 1.
- 2011年03月29日
- 1. PDO/MySQL(Windows版)の文字エンコーディング指定の不具合原因
- 2011年03月22日
- 1. PHP5.3.6からPDOの文字エンコーディング指定が可能となったがWindows版では不具合(脆弱性)あり
- 2011年01月27日
- 1. CSRF対策のトークンをワンタイムにしたら意図に反して脆弱になった実装例
- 2011年01月04日
- 1. escapeshellcmdの危険な実例
- 2011年01月01日
- 1. PHPのescapeshellcmdの危険性
- 2010年10月03日
- 1. 問題点の概要
- 2010年09月27日
- 1. 文字コードに起因する脆弱性を防ぐ「やや安全な」php.ini設定
- 2010年07月25日
- 1. ツッコミSPAM対策で、ツッコミ抜きのRSSフィードを用意しました
- 2010年07月01日
- 1. ぼくがPDOを採用しなかったわけ(Shift_JISによるSQLインジェクション)
- 2010年04月06日
- 1. PROXY(プロキシ)経由でのDNSリバインディングと対策
- 2010年04月05日
- 1. JavaアプレットのDNSリバインディングはJRE側で対策済みだった
- 2010年03月29日
- 1. DNSリバインディングによる無線LANパスフレーズの読み出しに成功
- 2010年03月25日
- 1. DNSリバインディングによるルータへの侵入実験
- 2010年02月22日
- 1. ケータイtwitter(twtr.jp)においてDNS Rebinding攻撃に対する脆弱性を発見・通報し、即座に修正された
- 2010年02月12日
- 1. かんたんログイン手法の脆弱性に対する責任は誰にあるのか
- 2010年01月18日
- 1. iモードブラウザ2.0のXMLHttpRequestでPOSTデータの扱いが困難になった
- 2009年10月19日
- 1. quoteメソッドの数値データ対応を検証する
- 2009年10月14日
- 1. htmlspecialchars/htmlentitiesはBMP外の文字を正しく扱えない
- 2009年10月09日
- 1. htmlspecialcharsのShift_JISチェック漏れによるXSS回避策
- 2009年09月30日
- 1. htmlspecialcharsは不正な文字エンコーディングをどこまでチェックするか
- 2009年09月24日
- 1. SQLの暗黙の型変換はワナがいっぱい
- 2009年09月18日
- 1. 文字エンコーディングバリデーションは自動化が望ましい
- 2009年09月14日
- 1. 既にあたり前になりつつある文字エンコーディングバリデーション
- 2009年08月05日
- 1. 携帯JavaScriptとXSSの組み合わせによる「かんたんログイン」なりすましの可能性
- 2009年03月28日
- 1. IPAは脆弱性の呼び方を統一して欲しい
- 2009年03月27日
- 2009年03月11日
- 1. U+00A5を用いたXSSの可能性
- 2008年12月22日
- 1. JavaとMySQLの組み合わせでUnicodeのU+00A5を用いたSQLインジェクションの可能性