Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

文字コードの脆弱性はこの3年間でどの程度対策されたか?

29,299 views

Published on

Published in: Technology
  • Be the first to comment

文字コードの脆弱性はこの3年間でどの程度対策されたか?

  1. 1. 文字コードの脆弱性は この3年間でどの程度対策されたか? 2014年2月19日 徳丸 浩
  2. 2. 徳丸浩の自己紹介 • 経歴 – 1985年 京セラ株式会社入社 – 1995年 京セラコミュニケーションシステム株式会社(KCCS)に出向・転籍 – 2008年 KCCS退職、HASHコンサルティング株式会社設立 • 経験したこと – 京セラ入社当時はCAD、計算幾何学、数値シミュレーションなどを担当 – その後、企業向けパッケージソフトの企画・開発・事業化を担当 – 1999年から、携帯電話向けインフラ、プラットフォームの企画・開発を担当 Webアプリケーションのセキュリティ問題に直面、研究、社内展開、寄稿などを開始 – 2004年にKCCS社内ベンチャーとしてWebアプリケーションセキュリティ事業を立ち 上げ • 現在 – HASHコンサルティング株式会社 代表 http://www.hash-c.co.jp/ – 独立行政法人情報処理推進機構 非常勤研究員 http://www.ipa.go.jp/security/ – 著書「体系的に学ぶ 安全なWebアプリケーションの作り方」(2011年3月) – 技術士(情報工学部門) Copyright © 2012-2014 HASH Consulting Corp. 2
  3. 3. 以下のデモは2010年のトークの 再演です(3年ちょっと前) Copyright © 2010-2014 HASH Consulting Corp. 3
  4. 4. デモ1:半端な先行バイトによるXSS • 半端な先行バイトとは – Shift_JIS、EUC-JP、UTF-8などマルチバイト文字の1 バイト目だけが独立して存在する状態 – 次の文字が、マルチバイト文字の2バイト目以降の文 字として「食われる」状況になる – input要素などの引用符「”」を食わせて、イベントハ ンドラを注入する攻撃 Copyright © 2010-2014 HASH Consulting Corp. 4
  5. 5. デモ1:PHPソース <?php session_start(); header('Content-Type: text/html; charset=Shift_JIS'); $p1 = @$_GET['p1']; $p2 = @$_GET['p2']; ?> <body> <form> PHP Version:<?php echo htmlspecialchars(phpversion(), ENT_NOQUOTES, 'Shift_JIS') ; ?><BR> <input name=p1 value="<?php echo htmlspecialchars($p1, ENT_QUOTES, 'Shift_JIS'); ?>"><BR> <input name=p2 value="<?php echo htmlspecialchars($p2, ENT_QUOTES, 'Shift_JIS'); ?>"><BR> <input type="submit" value="更新"> </form> </body> Copyright © 2010-2014 HASH Consulting Corp. 5
  6. 6. デモ1:半端な先行バイトによるXSS 閉じる引用符が食われた状態 <input name=p1 value="・><BR> <input name=p2 value=" onmouseover=alert(document.cookie)//"><BR> ここで最初の属性値がようやく終 了 第二の属性値がイベントハンドラ に • 半端な先行バイトによるXSSが発生する条件は、 以下のいずれかを満たす場合 – htmlspecialcharsの第3引数を指定していない – PHPの5.2.11以前あるいはPHP5.3.1以前を使用 • 対策としては、以下の両方を行う – PHPの最新版を使う – htmlspecialcharsの第3引数を指定する Copyright © 2010-2014 HASH Consulting Corp. 6
  7. 7. デモ2:UTF-8非最短形式によるパストラバー サル String msg = ""; String pathname = ""; try { String path = request.getParameter("path"); File f = new File(path); // パス名からファイル名を取り出す(PHPのbasename()) String filebody = f.getName(); // UTF-8としてデコード filebody = new String( filebody.getBytes("ISO-8859-1"), "UTF-8"); // ディレクトリを連結 pathname = "c:/home/data/" + filebody; // 以下ファイル読み出し FileReader fr = new FileReader(pathname); BufferedReader br = new BufferedReader(fr); ・・・ Copyright © 2010-2014 HASH Consulting Corp. 7
  8. 8. • 脆弱性が発生する条件(AND条件) – Java SE6 update10以前を使用 – 文字エンコーディング変換前にファイル名をチェックしてい る Copyright © 2010-2014 HASH Consulting Corp. 8
  9. 9. デモ3:5C問題によるSQLインジェクション • 5C問題とは – Shift_JIS文字の2バイト目に0x5Cが来る文字に起因する問題 ソ、表、能、欺、申、暴、十 … など出現頻度の高い文字が多 い – 0x5CがASCIIではバックスラッシュであり、ISO-8859-1など1 バイト文字と解釈された場合、日本語の1バイトがバックスラ ッシュとして取り扱われる – 一貫して1バイト文字として取り扱われれば脆弱性にならない が、 1バイト文字として取り扱われる場合と、Shift_JISとして取り 扱われる場合が混在すると脆弱性が発生する Copyright © 2010-2014 HASH Consulting Corp. 9
  10. 10. ソースコード(要点のみ) <?php header('Content-Type: text/html; charset=Shift_JIS'); $key = @$_GET['name']; if (! mb_check_encoding($key, 'Shift_JIS')) { die('文字エンコーディングが不正です'); } // MySQLに接続(PDO) $dbh = new PDO('mysql:host=localhost;dbname=books', 'phpcon', 'pass1'); // Shift_JISを指定 $dbh->query("SET NAMES sjis"); // プレースホルダによるSQLインジェクション対策 $sth = $dbh->prepare("SELECT * FROM books WHERE author=?"); $sth->setFetchMode(PDO::FETCH_NUM); // バインドとクエリ実行 $sth->execute(array($key)); ?> Copyright © 2010-2014 HASH Consulting Corp. 10
  11. 11. 5C問題によるSQLインジェクションの説明 Copyright © 2010-2014 HASH Consulting Corp. 11
  12. 12. 5C問題によるSQLインジェクションの対策 • データベース接続時に文字エンコーディングを正しく設 定する – 文字エンコーディングを設定できるライブラリを選択する – アプリケーション上で、文字エンコーディングを設定する • PDOは、PHP5.3.7から上記ができるようになった <?php $dbh = new PDO('mysql:host=xxx;dbname=xxx;charset=utf8', USERNAME, PASSWORD); $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $sth = $dbh->prepare("select * from test WHERE a=? and c=?"); $sth->bindParam(1, $a, PDO::PARAM_STR); $sth->bindParam(2, $c, PDO::PARAM_INT); $sth->execute(); Copyright © 2010-2014 HASH Consulting Corp. 12
  13. 13. デモ4:UTF-7によるXSS <?php session_start(); header('Content-Type: text/html; charset=EUCJP'); $p = @$_GET['p']; if (! mb_check_encoding($p, 'EUCJP')) { die('Invalid character encoding'); } ?> <body> <?php echo htmlspecialchars($p, ENT_NOQUOTES, 'EUCJP'); ?> </body> Copyright © 2010-2014 HASH Consulting Corp. 13
  14. 14. UTF-7によるXSSの説明 HTTPレスポンス EUCJPという文字エンコーディン HTTP/1.1 200 OK グをIEは認識できない(正しくは Content-Length: 187 EUC-JP) Content-Type: text/html; charset=EUCJP <body> +ADw-script+AD4-alert(document.cookie)+ADw-/script+AD4</body> IEはレスポンスの内容から、このコ ンテンツはUTF-7と判定する UTF-7として解釈されたコンテンツ <body> <script>alert(document.cookie)</script> </body> JavaScriptが 起動される Copyright © 2010-2014 HASH Consulting Corp. 14
  15. 15. デモ5:U+00A5によるSQLインジェクション Class.forName("com.mysql.jdbc.Driver"); Connection con = DriverManager.getConnection( "jdbc:mysql://localhost/books?user=phpcon&passwo rd=pass1"); String sql = "SELECT * FROM books where author=?"; // プレースホルダ利用によるSQLインジェクション対策 PreparedStatement stmt = con.prepareStatement(sql); // ? の場所に値を埋め込む(バインド) stmt.setString(1, key); ResultSet rs = stmt.executeQuery(); // クエリの実行 Copyright © 2010-2014 HASH Consulting Corp. 15
  16. 16. U+00A5によるSQLインジェクションの原理 IPA:安全なSQLの呼び出し方(http://www.ipa.go.jp/security/vuln/websecurity.html)より引用 16
  17. 17. U+00A5によるSQLインジェクションの条件と対 策 • 脆弱性が発生する条件 – JDBCとしてMySQL Connector/J 5.1.7以前を使用 – MySQLとの接続にShift_JISあるいはEUC-JPを使用 – 静的プレースホルダを使わず、エスケープあるいは動的プレー スホルダ(クライアントサイドのバインド機構)を利用してい る • 対策(どれか一つで対策になるがすべて実施を推奨) – MySQL Connector/Jの最新版を利用する – MySQLとの接続に使用する文字エンコーディングとして Unicode(UTF-8)を指定する (接続文字列にcharacterEncoding=utf8を指定する) – 静的プレースホルダを使用する (接続文字列にuseServerPrepStmts=trueを指定する) Copyright © 2010-2014 HASH Consulting Corp. 17
  18. 18. デモ6:U+00A5によるXSS // PHPでもU+00A5がバックスラッシュに変換されるパターンはないか <?php header('Content-Type: text/html; charset=Shift_JIS'); $p = @$_GET['p']; // JSエスケープ → '→' "→ " $p1 = preg_replace('/(?=['"])/u' , '', $p); $p2 = htmlspecialchars($p1, ENT_QUOTES, 'UTF-8'); ?> <html><head> <script type="text/javascript"> function foo($a) { document.getElementById("foo").innerText= $a; } </script></head> <body onload="foo('<?php echo $p2; ?>')"> p=<span id="foo"></span> [mbstring] mbstring.internal_encoding = UTF-8 </body> mbstring.http_input = auto </html> mbstring.http_output = cp932 mbstring.encoding_translation = On mbstring.detect_order = SJIS-win,UTF-8,eucJP-win Copyright © 2010-2014 HASH Consulting Corp. 18
  19. 19. U+00A5によるXSSが発生する原理と条件 • 脆弱性が発生する条件 – PHP5.3.3(以降)を利用している • それより前のバージョンでは、U+00A5は全角の「¥」に変換されて いた – 以下の文字エンコーディング • 入力:自動、あるいはなんらかの経路でU+00A5の文字が入る • 内部:UTF-8 • 出力:cp932 あるいは cp51932 Copyright © 2010-2014 HASH Consulting Corp. 19
  20. 20. デモ7: SQL Serverの文字集合問題 • ASP.NET + MS SQL Server + JSON • 1行掲示板 • 問題の原因はMS SQL Serverの以下のテーブル定義 CREATE TABLE chat1 ( id int IDENTITY (1, 1) NOT NULL , ctime datetime NOT NULL, body varchar (150) NOT NULL, json varchar (200) NOT NULL ) • json列にJSON形式に加工済みの投稿情報を格納して、閲 覧時には「そのまま」レスポンスとして返す • 問題はどこに? Copyright © 2010-2014 HASH Consulting Corp. 20
  21. 21. 投稿スクリプト sqlUrl = "Server=labo1; database=tokumaru;user id=sa;password=xxxxx” dbcon = New SqlConnection(sqlUrl) 'DBコネクション作成 dbcon.Open() 'DB接続 sqlStr = "insert into chat1 values(sysdatetime(), @body, @json)" dbcmd = New SqlCommand(sqlStr, dbcon) body = Request("body") e_body = Regex.Replace(body, "([<>'""])", "$1") e_body = Regex.Replace(e_body, "[rn]", "") ' JSON組み立て json = "{""ctime"":""" _ & DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") _ & """, ""body"":""" & e_body & ""“}" ' パラメータ dbcmd.Parameters.Add(New SqlParameter("@body", body)) dbcmd.Parameters.Add(New SqlParameter("@json", json)) dbResult = dbcmd.ExecuteNonQuery() Copyright © 2010-2014 HASH Consulting Corp. 21
  22. 22. 表示(HTML) <html><head><script src="jquery-1.4.3.min.js"></script> <script> function load() { var requester = new XMLHttpRequest(); requester.open('GET', 'json.aspx', true); requester.onreadystatechange = function() { if (requester.readyState == 4) { onloaded(requester); } }; requester.send(null); } function onloaded(requester) { res = requester.responseText; obj = eval("(" + res + ")"); $('#result').text(obj.ctime + ":" + obj.body); } </script></head><body> <input type="button" onclick="load();" value="hoge"/> <div id="result"></div></body> Copyright © 2010-2014 HASH Consulting Corp. 22
  23. 23. 表示(JSON) sqlUrl = "Server=labo1; database=tokumaru;user id=sa;password=xxxx" dbcon = New SqlConnection(sqlUrl) 'DBコネクション作成 dbcon.Open() 'DB接続 sqlStr = "select top 1 * from chat1 order by id desc" dbcmd = New SqlCommand(sqlStr, dbcon) 'SQL文実行 dataRead = dbcmd.ExecuteReader() dataRead.Read() Response.AddHeader("Cache-Control", "no-cache") Response.AddHeader("Content-Type", "application/json") 'ラベルに表示 Response.write(dataRead("json")) ' エスケープ済みなのでそのまま表示 Copyright © 2010-2014 HASH Consulting Corp. 23
  24. 24. 脆弱性の原因 • MS SQL Serverのvarcharは、CP932(マイクロソフト標 準キャラクタセットのShift_JIS)となる • Unicodeの列はnvarcharで宣言すること • varchar型の列にinsertする際に、Unicode→CP932の文字 エンコーディング(文字集合)の変換が発生する – U+00A5(円記号)は0x5Cに Copyright © 2010-2014 HASH Consulting Corp. 24
  25. 25. 対策 • 以下のいずれかを実施すれば脆弱性は発生しない – JSONの組み立てを表示(出力)の直前に行う • DB格納前の組み立ては危険 – 英数字以外の文字は、Unicode形式でエスケープする • uNNNNの形式 • いわゆる過剰エスケープ(個人的には嫌いだがやむなし) – 文字集合の変更をしない(nvarcahr型の列を使う) – JSONの解釈にevalを使わない • jQuery使うなら、とことん使えよ • JSONPの場合は、実質evalと同じなので他の対策で… • 「いずれか」ではなく「すべて実施」を推奨 Copyright © 2010-2014 HASH Consulting Corp. 25
  26. 26. 今はどうなの? Copyright © 2010-2014 HASH Consulting Corp. 26
  27. 27. これまでのデモを原因別に分類すると… • 文字エンコーディングとして不正なデータによる攻撃 – デモ1:半端な先行バイトによるXSS – デモ2:UTF-8非最短形式によるパストラバーサル • 文字エンコーディングとして不正でなく、マルチバイト 文字対応が不十分なもの – デモ3:5C問題によるSQLインジェクション – デモ4:UTF-7によるXSS • 文字集合の変更が原因となるもの – デモ5:U+00A5によるSQLインジェクション – デモ6:U+00A5によるXSS – デモ7:U+00A5によるスクリプトインジェクション Copyright © 27 2010 HASH
  28. 28. 対応状況まとめ Copyright © 2010-2014 HASH Consulting Corp. 28
  29. 29. IE側の対応(1) IE側でも、「半端な先行バイト」によるXSS 対策が入っている。実施時期は不明。 Shift_JISとして不正な並びがある場合は、2 バイト1文字とせずに、別の文字と解釈する。 Copyright © 2010-2014 HASH Consulting Corp. 29
  30. 30. IE側の対応(2) Copyright © 2010-2014 HASH Consulting Corp. 30
  31. 31. UTF-7 XSSを巡る冒険 • IEの古典的なUTF-7 XSSは、MS10-090(2010年12月)にて改修され ている – 文字エンコーディング推測の変更 • ただし、MS10-090のドキュメントには明記されていない • MS10-090に含まれるIEの改修は2種類 – CVE-2010-3342とCVE-2010-3342 – どちらもキャッシュ周りの脆弱性…同じもののように見える • 以下は、はせがわようすけさんの推測(MS確認済み) – CVE-2010-3342は文字コード関連の脆弱性の修正である – CVE-2010-3348はキャッシュ周りの脆弱性の修正である – MS10-090内の記述が誤っている • script要素で文字エンコーディングを指定する攻撃方法は依然とし て有効なので注意 Copyright © 2010-2014 HASH Consulting Corp. 31
  32. 32. まとめ • 文字コードに起因する脆弱性は、プラットフォーム側で の整備が進み安全性が強化されつつある • 最新のソフトウェアを使い、正しく文字エンコーディン グを設定する • アプリ側で文字エンコーディングのバリデーションをし なくても脆弱性にならないことが本来の姿 • 文字集合の問題は残る課題 – できるだけ文字集合を変更しない(Unicodeで統一) – JavaScriptなら、ユニコード・エスケープにすると安全性が高 まる。 △ " → " ○ " → u0022 Copyright © 2010-2014 HASH Consulting Corp. 32

×