何故かあたり前にならない文字エンコーディングバリデーション

(Last Updated On: 2018年8月8日)

私が4年前(2005年)に「Webアプリセキュリティ対策入門」を執筆していた時には、既に壊れた文字エンコーディングなどの不正な文字エンコーディングを利用したJavaScriptインジェクションやSQLインジェクション攻撃は比較的広く知られていました。この問題は当時のスラッシュドットジャパンでも取り上げられていました。/.で取り上げられたので、そこら中のWebサイトとユーザが被害に合うのでは?とヒヤヒヤしたので良く覚えています。

不正な文字エンコーディングを利用した攻撃は、文字エンコーディングを厳格に取り扱い、文字エンコーディングをバリデーションすれば無くなります。これを怠ると、システムのどこで問題が発生するか予想できなくなります。つまり、いい加減に文字エンコーディングを取り扱うと安全なシステムは作れないのです。

参考:エンジニア向けにもう少し解りやすいブログを最近書いています。

エンジニアなら理解る文字エンコーディングバリデーションの必要性


参考:本当は怖い文字コードの話
http://gihyo.jp/admin/serial/01/charcode/0006

このよう事は簡単に理解できると思っていたので、近い将来(1年以内)に文字エンコーディングのバリデーションはあたり前になる、と考えていました。2005年には一部のPHPプログラマは文字エンコーディングのバリデーションに文字エンコーディング変換関数を利用していました。2006年初めには文字エンコーディングバリデーション専用のmb_check_encoding関数も追加されました。

「Webアプリセキュリティ対策入門」では、壊れた文字エンコーディングに対する対策はバリデーションで必要なチェックの一つ、として取り扱いました。近い将来あたり前になって攻撃できなくなる脆弱性に一つの項目を与える必要も無いこと、出版時点では周り中が脆弱なアプリケーションであること、を理由に一つの独立した項目にしませんでした。(しかし、現在でも脆弱なWebアプリばかり…)

2005年当時、近い将来この問題は解決されると信じていました。しかし、残念ながらこの予想は全く外れました。JavaScriptインジェクションの脆弱性が2000年に注意喚起されて数年経っても、多くのWeb開発者や運営者は全く危険性を理解せず、対策も取らなかった事、2005年当時でも(文字エンコーディングベースの攻撃を除けば)完全に防げるSQLインジェクションもあたり前のように対策が取られていなかった事と同様である、と予測しておくべきでした。

Railsの開発者は現在になっても、その危険性を指摘されても理解出来かなったようです。

参考:RubyOnRailsのXSS脆弱性がTwitterとBasecampとぼくの魂を殺した
http://jp.techcrunch.com/archives/20090903rubyonrails-xss-vulnerability-claims-twitter-basecamp-and-my-confidence/

Railsの開発者だけを責めるのは不当でしょう。私はPHPセキュリティレスポンスチームもこの問題に関する理解がRailsの開発者と同程度である事も知っています。PHP 4.4.9がリリースされる際に、文字エンコーディングベースの攻撃に脆弱になるため、バックポートが必要な複数のパッチの適用を提案したのですが、理解されませんでした。mbstringがデフォルトモジュールとなっていない事もセキュリティに対するインパクトを理解していないからです。

Perlについては小飼 弾氏が今年になって、文字エンコーディング変換を利用した文字エンコーディングバリデーションを提案しているので、日本のPerl開発者は一部の(先進的?)PHP開発者と同程度の対策は取るようになると思います。

参考:perl – EnodeでXSSを防ぐ
http://blog.livedoor.jp/dankogai/archives/51184112.html

Ruby、Pythonについても、何方か有名な方が文字エンコーディング変換を利用したバリデーションをする方法をブログに書くべきです。
(RoRの脆弱性に関連してRuby1.9では安全、と解説されていますが、それはRuby1.9は不正な文字エンコーディングを受け付けないからです。個人的には明示的にバリデーションコードで検出する方が良いと考えています。クライアントからの入力は文字列のみでなくイメージ等のバイナリも含まれるからです。)

私はこの問題についてブログ、書籍、雑誌、Webマガジン、セミナーなどで話をしていますが、残念ながらPHPユーザにも十分声が届いていないのが現状です。

ブログで一斉に取り上げて、いい加減文字エンコーディング問題を無くしませんか?

文字エンコーディングを利用した攻撃を防ぐ基本

・全ての入力文字列の文字エンコーディングをバリデーションする

(e.g. PHPならmb_check_encoding関数、他の言語ならエンコーディング変換を利用する等。不正なエンコーディングを検出したら”必ず”プログラムの実行を停止。)
・文字エンコーディングを厳格に取り扱う
(e.g. HTTPヘッダで文字エンコーディングを指定。DB等では必ずAPIを利用して文字エンコーディングを指定し、DBのAPIでエスケープ、など)
・データベースなどで「バイナリ」に近いエンコーディングは絶対に利用しない
(e.g. ASCIIなど)

最近では少なくなったと思いますが、HTTPヘッダで文字エンコーディングを指定すべき、との指摘は2000年にCERTがXSSの脆弱性への注意喚起を行った時から言われています。未だに大手サイトで散見される問題です。(セキュリティホールとはなり得ない部分ですがGoogleでさえHTTPヘッダで文字エンコーディングを指定していないケースがあります)

MySQLでは”SET NAMES”、PostgreSQLでは”SET client_encoding TO”(新しいPostgreSQLでは”SET NAMES”も利用可能)は「アプリケーションから使ってはならない文」です。APIから文字エンコーディング指定しないと、同じくAPIであるエスケープ関数が文字エンコーディングを考慮したエスケープが出来ません。(SJISのMySQL環境では致命的)

データベースにおけるこの問題は2005年末に明らかになり、2006年春頃には問題を解決するAPIが提供されました。日本ではSJISを利用しているケース多く、影響が非常に大きいので”SET NAMES”を利用したエンコーディング指定は直ぐに無くなる、と思っていたのですが、これも予想に反した状態になっています。

「Webアプリセキュリティ対策入門」にはこれらの事に簡単に触れているので、読んだ方であれば文字エンコーディングを利用した攻撃に脆弱なアプリケーションを作る事は無いと思いますが、売れてないないですからね… アマゾンのレビューが酷いせいかな?とにかく書く事だけに一生懸命でしたから、執筆時点は…

手前味噌ですがWebセキュリティ、特にプログラミングやセキュアなコーディングの心得については「Webアプリセキュリティ対策入門」は割と良くまとまっていると思います。前半部分は開発者でない方でも読めて脆弱性の危険性だけは理解できるように書き、後半は具体的な対策をPHPを用いて紹介しています。

久しぶりにアマゾンのレビュー見ましたが、ほんと酷い評価(苦笑 でもセキュリティ標準を読んだ事がある、せめて名前や内容を正しく解説できるWeb開発者はあたり前にいるとは思えません。誤字・脱字は自分でも見つけましたが、こういう本の評価に重要なのでしょうか?内容が正しいかどうかは技術者であれば判断できると思います。もしかしてコード監査で酷い目に合わせてしまった方なのかな?(汗

(重版していないので今買っても誤字・脱字は直ってません。悪しからずご了承ください)

JavaScriptの実行を制限するNoScript拡張などを利用する以外に、ユーザとして文字エンコーディングを利用した攻撃のリスクを軽減する方法があります。ブラウザの文字エンコーディングの自動認識を「オフ」にすれば、かなりリスクを軽減できます。

たいていデフォルトで有効になっているので必ず「オフ」にしましょう。

追記:年度を一年勘違いしていたので修正しました。

投稿者: yohgaki