---
title: 文字コードの脆弱性はこの3年間でどの程度対策されたか?
tags:  #security  
author: [徳丸 浩](https://www.docswell.com/user/ockeghem)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/PLE1DX5X7G.jpg?width=480
description: 文字コードの脆弱性はこの3年間でどの程度対策されたか? by 徳丸 浩
published: February 25, 14
canonical: https://www.docswell.com/s/ockeghem/ZX6P75-owasp20134021
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/PLE1DX5X7G.jpg)

文字コードの脆弱性は
この3年間でどの程度対策されたか?
2014年2月19日
徳丸 浩


# Page. 2

![Page Image](https://bcdn.docswell.com/page/8GEWYN5KJ2.jpg)

徳丸浩の自己紹介
•
経歴
– 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


# Page. 3

![Page Image](https://bcdn.docswell.com/page/W47ZX3NNJ3.jpg)

以下のデモは2010年のトークの
再演です（3年ちょっと前）
Copyright © 2010-2014 HASH Consulting Corp.
3


# Page. 4

![Page Image](https://bcdn.docswell.com/page/KYJ64X89EV.jpg)

デモ1:半端な先行バイトによるXSS
• 半端な先行バイトとは
– Shift_JIS、EUC-JP、UTF-8などマルチバイト文字の1バイ
ト目だけが独立して存在する状態
– 次の文字が、マルチバイト文字の2バイト目以降の文字と
して「食われる」状況になる
– input要素などの引用符「”」を食わせて、イベントハンドラを
注入する攻撃
Copyright © 2010-2014 HASH Consulting Corp.
4


# Page. 5

![Page Image](https://bcdn.docswell.com/page/5GJ5QX9DE4.jpg)

デモ１：PHPソース
&lt;?php
session_start();
header(&#039;Content-Type: text/html; charset=Shift_JIS&#039;);
$p1 = @$_GET[&#039;p1&#039;];
$p2 = @$_GET[&#039;p2&#039;];
?&gt;
&lt;body&gt;
&lt;form&gt;
PHP Version:&lt;?php
echo htmlspecialchars(phpversion(), ENT_NOQUOTES,
&#039;Shift_JIS&#039;); ?&gt;&lt;BR&gt;
&lt;input name=p1 value=&quot;&lt;?php echo
htmlspecialchars($p1, ENT_QUOTES, &#039;Shift_JIS&#039;); ?&gt;&quot;&gt;&lt;BR&gt;
&lt;input name=p2 value=&quot;&lt;?php echo
htmlspecialchars($p2, ENT_QUOTES, &#039;Shift_JIS&#039;); ?&gt;&quot;&gt;&lt;BR&gt;
&lt;input type=&quot;submit&quot; value=&quot;更新&quot;&gt;
&lt;/form&gt;
&lt;/body&gt;
Copyright © 2010-2014 HASH Consulting Corp.
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/4LE3VX2QJ5.jpg)

デモ1:半端な先行バイトによるXSS
閉じる引用符が食われた状態
&lt;input name=p1 value=&quot;・&gt;&lt;BR&gt;
&lt;input name=p2 value=&quot; onmouseover=alert(document.cookie)//&quot;&gt;&lt;BR&gt;
ここで最初の属性値がようやく終了
第二の属性値がイベントハンドラに
• 半端な先行バイトによるXSSが発生する条件は、以
下のいずれかを満たす場合
– htmlspecialcharsの第3引数を指定していない
– PHPの5.2.11以前あるいはPHP5.3.1以前を使用
• 対策としては、以下の両方を行う
– PHPの最新版を使う
– htmlspecialcharsの第3引数を指定する
Copyright © 2010-2014 HASH Consulting Corp.
6


# Page. 7

![Page Image](https://bcdn.docswell.com/page/V8ED82ZWEG.jpg)

デモ2:UTF-8非最短形式によるパストラバーサル
String msg = &quot;&quot;;
String pathname = &quot;&quot;;
try {
String path = request.getParameter(&quot;path&quot;);
File f = new File(path);
// パス名からファイル名を取り出す(PHPのbasename())
String filebody = f.getName();
// UTF-8としてデコード
filebody = new String(
filebody.getBytes(&quot;ISO-8859-1&quot;), &quot;UTF-8&quot;);
// ディレクトリを連結
pathname = &quot;c:/home/data/&quot; + filebody;
// 以下ファイル読み出し
FileReader fr = new FileReader(pathname);
BufferedReader br = new BufferedReader(fr);
・・・
Copyright © 2010-2014 HASH Consulting Corp.
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/4V7P81DX78.jpg)

• 脆弱性が発生する条件(AND条件)
– Java SE6 update10以前を使用
– 文字エンコーディング変換前にファイル名をチェックしている
Copyright © 2010-2014 HASH Consulting Corp.
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/L2JVNY13EQ.jpg)

デモ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


# Page. 10

![Page Image](https://bcdn.docswell.com/page/Z5EGK92Y7L.jpg)

ソースコード（要点のみ）
&lt;?php
header(&#039;Content-Type: text/html; charset=Shift_JIS&#039;);
$key = @$_GET[&#039;name&#039;];
if (! mb_check_encoding($key, &#039;Shift_JIS&#039;)) {
die(&#039;文字エンコーディングが不正です&#039;);
}
// MySQLに接続(PDO)
$dbh = new PDO(&#039;mysql:host=localhost;dbname=books&#039;, &#039;phpcon&#039;, &#039;pass1&#039;);
// Shift_JISを指定
$dbh-&gt;query(&quot;SET NAMES sjis&quot;);
// プレースホルダによるSQLインジェクション対策
$sth = $dbh-&gt;prepare(&quot;SELECT * FROM books WHERE author=?&quot;);
$sth-&gt;setFetchMode(PDO::FETCH_NUM);
// バインドとクエリ実行
$sth-&gt;execute(array($key));
?&gt;
Copyright © 2010-2014 HASH Consulting Corp.
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/V4JQNWP6JP.jpg)

5C問題によるSQLインジェクションの説明
Copyright © 2010-2014 HASH Consulting Corp.
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/DK74GKYMJ1.jpg)

5C問題によるSQLインジェクションの対策
• データベース接続時に文字エンコーディングを正しく設定する
– 文字エンコーディングを設定できるライブラリを選択する
– アプリケーション上で、文字エンコーディングを設定する
• PDOは、PHP5.3.7から上記ができるようになった
&lt;?php
$dbh = new PDO(&#039;mysql:host=xxx;dbname=xxx;charset=utf8&#039;,
USERNAME, PASSWORD);
$dbh-&gt;setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$sth = $dbh-&gt;prepare(&quot;select * from test WHERE a=? and c=?&quot;);
$sth-&gt;bindParam(1, $a, PDO::PARAM_STR);
$sth-&gt;bindParam(2, $c, PDO::PARAM_INT);
$sth-&gt;execute();
Copyright © 2010-2014 HASH Consulting Corp.
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/PLJ1DX6YEG.jpg)

デモ4:UTF-7によるXSS
&lt;?php
session_start();
header(&#039;Content-Type: text/html;
charset=EUCJP&#039;);
$p = @$_GET[&#039;p&#039;];
if (! mb_check_encoding($p, &#039;EUCJP&#039;)) {
die(&#039;Invalid character encoding&#039;);
}
?&gt;
&lt;body&gt;
&lt;?php echo
htmlspecialchars($p, ENT_NOQUOTES, &#039;EUCJP&#039;); ?&gt;
&lt;/body&gt;
Copyright © 2010-2014 HASH Consulting Corp.
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/8GJWYNW172.jpg)

UTF-7によるXSSの説明
HTTPレスポンス
EUCJPという文字エンコーディングを
IEは認識できない(正しくはEUC-JP)
HTTP/1.1 200 OK
Content-Length: 187
Content-Type: text/html; charset=EUCJP
&lt;body&gt;
+ADw-script+AD4-alert(document.cookie)+ADw-/script+AD4&lt;/body&gt;
IEはレスポンスの内容から、このコン
テンツはUTF-7と判定する
UTF-7として解釈されたコンテンツ
&lt;body&gt;
&lt;script&gt;alert(document.cookie)&lt;/script&gt;
&lt;/body&gt;
JavaScriptが
起動される
Copyright © 2010-2014 HASH Consulting Corp.
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/W4EZX35X73.jpg)

デモ5:U+00A5によるSQLインジェクション
Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
Connection con = DriverManager.getConnection(
&quot;jdbc:mysql://localhost/books?user=phpcon&amp;passwo
rd=pass1&quot;);
String sql = &quot;SELECT * FROM books where author=?&quot;;
// プレースホルダ利用によるSQLインジェクション対策
PreparedStatement stmt =
con.prepareStatement(sql);
// ? の場所に値を埋め込む（バインド）
stmt.setString(1, key);
ResultSet rs = stmt.executeQuery(); // クエリの実行
Copyright © 2010-2014 HASH Consulting Corp.
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/KY764X9PJV.jpg)

U+00A5によるSQLインジェクションの原理
IPA:安全なSQLの呼び出し方（http://www.ipa.go.jp/security/vuln/websecurity.html）より引用
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/5G75QXNPJ4.jpg)

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


# Page. 18

![Page Image](https://bcdn.docswell.com/page/V9J2PX5ZJR.jpg)

デモ6:U+00A5によるXSS
// PHPでもU+00A5がバックスラッシュに変換されるパターンはないか
&lt;?php
header(&#039;Content-Type: text/html; charset=Shift_JIS&#039;);
$p = @$_GET[&#039;p&#039;];
// JSエスケープ \→\\ &#039;→\&#039; &quot;→ \&quot;
$p1 = preg_replace(&#039;/(?=[\\\\\\\&#039;\\&quot;])/u&#039; , &#039;\\&#039;, $p);
$p2 = htmlspecialchars($p1, ENT_QUOTES, &#039;UTF-8&#039;);
?&gt;
&lt;html&gt;&lt;head&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
function foo($a) {
document.getElementById(&quot;foo&quot;).innerText= $a;
}
&lt;/script&gt;&lt;/head&gt;
&lt;body onload=&quot;foo(&#039;&lt;?php echo $p2; ?&gt;&#039;)&quot;&gt;
p=&lt;span id=&quot;foo&quot;&gt;&lt;/span&gt;
[mbstring]
mbstring.internal_encoding = UTF-8
&lt;/body&gt;
mbstring.http_input = auto
&lt;/html&gt;
mbstring.http_output = cp932
mbstring.encoding_translation = On
mbstring.detect_order = SJIS-win,UTF-8,eucJP-win
Copyright © 2010-2014 HASH Consulting Corp.
18


# Page. 19

![Page Image](https://bcdn.docswell.com/page/5DEY58KNEM.jpg)

U+00A5によるXSSが発生する原理と条件
• 脆弱性が発生する条件
– PHP5.3.3(以降)を利用している
• それより前のバージョンでは、U+00A5は全角の「￥」に変換されていた
– 以下の文字エンコーディング
• 入力:自動、あるいはなんらかの経路でU+00A5の文字が入る
• 内部：UTF-8
• 出力：cp932 あるいは cp51932
Copyright © 2010-2014 HASH Consulting Corp.
19


# Page. 20

![Page Image](https://bcdn.docswell.com/page/2VJNNQRVJ8.jpg)

デモ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


# Page. 21

![Page Image](https://bcdn.docswell.com/page/GYE9RDMV73.jpg)

投稿スクリプト
sqlUrl = &quot;Server=labo1; database=tokumaru;user id=sa;password=xxxxx”
dbcon = New SqlConnection(sqlUrl) &#039;ＤＢコネクション作成
dbcon.Open()
&#039;DB接続
sqlStr = &quot;insert into chat1 values(sysdatetime(), @body, @json)&quot;
dbcmd = New SqlCommand(sqlStr, dbcon)
body = Request(&quot;body&quot;)
e_body = Regex.Replace(body, &quot;([&lt;&gt;\\&#039;&quot;&quot;])&quot;, &quot;\$1&quot;)
e_body = Regex.Replace(e_body, &quot;[\r\n]&quot;, &quot;&quot;)
&#039; JSON組み立て
json = &quot;{&quot;&quot;ctime&quot;&quot;:&quot;&quot;&quot; _
&amp; DateTime.Now.ToString(&quot;yyyy/MM/dd HH:mm:ss&quot;) _
&amp; &quot;&quot;&quot;, &quot;&quot;body&quot;&quot;:&quot;&quot;&quot; &amp; e_body &amp; &quot;&quot;“}&quot;
&#039; パラメータ
dbcmd.Parameters.Add(New SqlParameter(&quot;@body&quot;, body))
dbcmd.Parameters.Add(New SqlParameter(&quot;@json&quot;, json))
dbResult = dbcmd.ExecuteNonQuery()
Copyright © 2010-2014 HASH Consulting Corp.
21


# Page. 22

![Page Image](https://bcdn.docswell.com/page/5GE8W3L47D.jpg)

表示（HTML）
&lt;html&gt;&lt;head&gt;&lt;script src=&quot;jquery-1.4.3.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
function load()
{
var requester = new XMLHttpRequest();
requester.open(&#039;GET&#039;, &#039;json.aspx&#039;, true);
requester.onreadystatechange = function() {
if (requester.readyState == 4) {
onloaded(requester);
}
};
requester.send(null);
}
function onloaded(requester)
{
res = requester.responseText;
obj = eval(&quot;(&quot; + res + &quot;)&quot;);
$(&#039;#result&#039;).text(obj.ctime + &quot;:&quot; + obj.body);
}
&lt;/script&gt;&lt;/head&gt;&lt;body&gt;
&lt;input type=&quot;button&quot; onclick=&quot;load();&quot; value=&quot;hoge&quot;/&gt;
&lt;div id=&quot;result&quot;&gt;&lt;/div&gt;&lt;/body&gt;
Copyright © 2010-2014 HASH Consulting Corp.
22


# Page. 23

![Page Image](https://bcdn.docswell.com/page/MLELNVLVJR.jpg)

表示(JSON)
sqlUrl = &quot;Server=labo1; database=tokumaru;user id=sa;password=xxxx&quot;
dbcon = New SqlConnection(sqlUrl)
&#039;ＤＢコネクション作成
dbcon.Open() &#039;DB接続
sqlStr = &quot;select top 1 * from chat1 order by id desc&quot;
dbcmd = New SqlCommand(sqlStr, dbcon)
&#039;ＳＱＬ文実行
dataRead = dbcmd.ExecuteReader()
dataRead.Read()
Response.AddHeader(&quot;Cache-Control&quot;, &quot;no-cache&quot;)
Response.AddHeader(&quot;Content-Type&quot;, &quot;application/json&quot;)
&#039;ラベルに表示
Response.write(dataRead(&quot;json&quot;)) &#039; エスケープ済みなのでそのまま表示
Copyright © 2010-2014 HASH Consulting Corp.
23


# Page. 24

![Page Image](https://bcdn.docswell.com/page/54JMXGMN7W.jpg)

脆弱性の原因
• MS SQL Serverのvarcharは、CP932（マイクロソフト標準キ
ャラクタセットのShift_JIS）となる
• Unicodeの列はnvarcharで宣言すること
• varchar型の列にinsertする際に、Unicode→CP932の文字
エンコーディング（文字集合）の変換が発生する
– U+00A5（円記号）は0x5Cに
Copyright © 2010-2014 HASH Consulting Corp.
24


# Page. 25

![Page Image](https://bcdn.docswell.com/page/ZPJRNZV479.jpg)

対策
• 以下のいずれかを実施すれば脆弱性は発生しない
– JSONの組み立てを表示（出力）の直前に行う
• DB格納前の組み立ては危険
– 英数字以外の文字は、Unicode形式でエスケープする
• \uNNNNの形式
• いわゆる過剰エスケープ（個人的には嫌いだがやむなし）
– 文字集合の変更をしない（nvarcahr型の列を使う）
– JSONの解釈にevalを使わない
• jQuery使うなら、とことん使えよ
• JSONPの場合は、実質evalと同じなので他の対策で…
• 「いずれか」ではなく「すべて実施」を推奨
Copyright © 2010-2014 HASH Consulting Corp.
25


# Page. 26

![Page Image](https://bcdn.docswell.com/page/NPEXN9ZZJX.jpg)

今はどうなの?
Copyright © 2010-2014 HASH Consulting Corp.
26


# Page. 27

![Page Image](https://bcdn.docswell.com/page/63EKNP8VED.jpg)

これまでのデモを原因別に分類すると…
• 文字エンコーディングとして不正なデータによる攻撃
– デモ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


# Page. 28

![Page Image](https://bcdn.docswell.com/page/4L73VXMQE5.jpg)

対応状況まとめ
Copyright © 2010-2014 HASH Consulting Corp.
28


# Page. 29

![Page Image](https://bcdn.docswell.com/page/V87D826W7G.jpg)

IE側の対応(1)
IE側でも、「半端な先行バイト」によるXSS対策
が入っている。実施時期は不明。
Shift_JISとして不正な並びがある場合は、2バイ
ト1文字とせずに、別の文字と解釈する。
Copyright © 2010-2014 HASH Consulting Corp.
29


# Page. 30

![Page Image](https://bcdn.docswell.com/page/4VJP81YXJ8.jpg)

IE側の対応(2)
Copyright © 2010-2014 HASH Consulting Corp.
30


# Page. 31

![Page Image](https://bcdn.docswell.com/page/L2EVNYG37Q.jpg)

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内の記述が誤っている
• iframeやscript要素で文字エンコーディングを指定する攻撃方法は依然
として有効なので注意
Copyright © 2010-2014 HASH Consulting Corp.
31


# Page. 32

![Page Image](https://bcdn.docswell.com/page/Z57GK98YJL.jpg)

まとめ
• 文字コードに起因する脆弱性は、プラットフォーム側での整備
が進み安全性が強化されつつある
• 最新のソフトウェアを使い、正しく文字エンコーディングを設定
する
• アプリ側で文字エンコーディングのバリデーションをしなくても
脆弱性にならないことが本来の姿
• 文字集合の問題は残る課題
– できるだけ文字集合を変更しない(Unicodeで統一)
– JavaScriptなら、ユニコード・エスケープにすると安全性が高まる。
△ &quot; → \&quot;
○ &quot; → \u0022
Copyright © 2010-2014 HASH Consulting Corp.
32


