# 6章 文字コードとセキュリティ ###### tags: `安全なWebアプリケーションの作り方` 勉強会用資料 ## 6.3 文字エンコーディング ### UTF-8 * Unicodeの文字エンコーディングの1つ * US-ASCⅡと互換性のある符号化方式 下記表に従ってUnicodeのスカラ値(符号空間のうち代用符号位置を除く符号位置)の範囲ごとに符号化することで、符号化後の文字データは4バイトの可変長になる。 <summary>UTF-8のビットパターン</summary> | スカラ値の範囲 | UTF-8ビットパターン | ビット長 | | -------------- | --------------------------------------------------- | -------- | | 00〜7F | ==0xxxxxxx== | 7ビット | | 80〜7FF | ==110xxxxx== ==10xxxxxx== | 11ビット | | 800〜FFFF | ==1110xxxx== ==10xxxxxx== ==10xxxxxx== | 16ビット | | 10000〜10FFF | ==11110xxx== ==10xxxxxx== ==10xxxxxx== ==10xxxxxx== | 21ビット | ビットパターンを16進数でみると、、、 `0xxxxxxx = 00~7F` `10xxxxxx = 80~BF` `110xxxxx = C2~DF` `1110xxxx = E0~EF` `11110xxx = F0~F7` * テキスト図6-17参照 * 各領域の重なりがないので、文字列中の1バイトに着目した場合に、文字の先頭か後続バイトなのかの判別が可能 * 日本語を符号化する場合、JIS X 208の漢字はおおむね3バイトで符号化される * ただし、図6-18のように4バイトで符号化されるものもある <summary>図6-18 𠮷田をUTF-8で符号化した場合</summary> | 𠮷(U+20BB7) | 田(U+7530) | | ----------- | -------- | | F0 A0 AE B7 | E7 94 B0 | :::info UTF-8は現在ある文字コードの中で最も扱いやすく安全な方式 ただし非最短形式の問題には注意 ::: ### UTF-8の非最短形式の問題 UTF-8ではU+0000〜U+007Fまでの範囲の文字はUS-ASCIIと互換を持ち、`0x00~0x7F`となる。多くのOSでのパス区切り記号として使われるスラッシュ「/」(⁠U+002F)は`0x2F`となる。 しかし、`U+0000~U+007F`以外の欄に無理やり当てはめて、1バイト以外の形式で表現することができてしまう。 <summary>表6-4 「/」の非最短形式</summary> | nバイト | 範囲 | | ------- | ---- | | 1バイト | 0x2F | | 2バイト | 0xC0 0xAF | | 3バイト | 0xE0 0x80 0xAF | | 4バイト | 0xF0 0x80 0x80 0xAF | <summary>3バイトの場合</summary>summary> 1. bin(2F) = <font color="#ffbf7f">0000 0000 0010 1111</font> 2. 無理やり3バイトでエンコード <font color="#7fbfff">1110</font><font color="#ffbf7f">0000</font> <font color="#7fbfff">10</font><font color="#ffbf7f">0000 00</font> <font color="#7fbfff">10</font><font color="#ffbf7f">10 1111</font> 3. 結果 0xE0 0x80 0xAF 参考:[本当は怖い文字コードの話](https://gihyo.jp/admin/serial/01/charcode/0004) ### UTF-8の非最短形式による脆弱性 非最短形式による脆弱性が発生するシナリオは以下の通り。 * セキュリティ上のチェックの際は、非最短形式`0xC0 0xAF`がスラッシュ'0x2F'でないとみなされる * ファイル名などとして非最短形式'0xC0 0xAF'を使う際にはスラッシュとしてみなされる UTF-8の非最短形式で表記したスラッシュを他の文字エンコーディング(Shift-JIS、UTF-16)に機械的に変換すると、通常のスラッシュに変更されてしまう。 対策としては、 * 自前でUTF-8を処理しないこと。 * 最新版の処理系を用いること。 ## 6.4 文字コードによる脆弱性の発生要因まとめ 下記の3つのタイプに分類される。 ### 文字エンコーディングとして不正なバイト列による脆弱性 半端な先行バイトと非最短形式が該当する。 * [MS00-057](https://docs.microsoft.com/ja-jp/security-updates/securitybulletins/2000/ms00-057) * [Apache Tomcat におけるディレクトリトラバーサルの脆弱性](https://jvndb.jvn.jp/ja/contents/2008/JVNDB-2008-001611.html) ### 文字エンコーディングの扱い不備による脆弱性 「5C」問題が代表的。 * マルチバイト文字列処理が考慮されていない、または不完全 * [UTF-7を悪用したXSS](https://gihyo.jp/admin/serial/01/charcode/0001) ### 文字集合の変更に起因する脆弱性 Unicodeの円記号「¥」(U+00A5)を他の文字集合に変更した際、バックスラッシュ「\」(0x5C)に変換されることによる脆弱性。 * [MySQL Connector/J における SQL インジェクションの脆弱性](https://jvn.jp/jp/JVN59748723/index.html) ## 6.5 文字コードを正しく扱うために Webアプリ上の入力・出力・処理で対策する。 * アプリケーション全体を通して文字集合を統一する * Unicodeが望ましい * 入力時に不正な文字エンコーディングをエラーにする * 入力時点でチェックする * 処理の中で文字エンコーディングを正しく扱う * マルチバイト文字に対応した処理系・関数のみを使う * 関数の引数として、文字エンコーディングを明示する * 出力時に文字エンコーディングを正しく指定する * HTTPレスポンスヘッダの`Content-Type`を正しく指定(4.3節参照) * データベースの文字エンコーディングを正しく指定する(4.4節参照) * 文字エンコーディングの指定が必要な箇所は漏れなく指定する ## 6.6 まとめ 文字コードによる脆弱性の身近な対策としては、文字化けをなくすことが有効。まずは以下を確認すべき。 * 不正な文字エンコーディングではエラーになるか代替文字(U+FFFD)に変換されること * 「表」「ソ」「能」などが正しく登録、表示されること * 「尾骶骨テスト」と「つちよしテスト」をクリアすること <summary>対策まとめ</summary> :::info * アプリケーション全体を通して文字集合をUnicodeに統一する * 入力時に不正な文字エンコーディングをエラーにする * 処理の中で文字エンコーディングを正しく扱う * 出力時に文字エンコーディングを正しく指定する ::: 以上