第2回: Unicode から Shift_JIS への変換(その2)

前回の続きの前に少しだけ。RIPさんの質問

ところで、今回の内容を読んで気になっているというか悩んでる事。
今回の文章中の「Unicode」は、厳密には「UTF-16」と理解していいのだろか?

Windows 上での Unicode の標準的なエンコーディングですので、UTF-16LE と考えてください。ただし、いちいち UnicodeUTF-16、UTF-16LE という表記を使い分けるのも面倒なのと、Microsoft の文書類のほとんどが Unicode という表記になっており、それとの整合を合わせるためにも、UTF-16 または UTF-16LE と明記しなければならない状況でない限りは今後も Unicode と書くことにします。
さて、前回WideCharToMultiByte を使用して UnicodeShift_JIS に変換する場合に、WC_NO_BEST_FIT_CHARS フラグを設定しなければ「似た文字への変換」がなされる、という話をしました。今回は、その「似た文字への変換」が引き起こすセキュリティ上の問題点についての説明です。

円記号
Unicode から Shift_JIS への変換にて U+00A5(¥) の円記号が 0x5C(\) のバックスラッシュに変換されます。そのため、文字列のチェック後に Shift_JIS への変換処理がある場合、変換後の文字列に 0x5C が混入し、ディレクトリトラバーサルの発生やその他のメタ文字として扱われる可能性があります。
XSS
ヤマガタさんも書かれていますが、U+00DF U+00C7 U+00A9 U+00CE U+0050 U+00FE (ßÇ©ÎPþ)という Unicode の文字列は、Shift_JIS に変換されると "sCRIPT" になります。WAF などで単純に、Unicode 文字列の "<SCRIPT>" だけを検査しており、その後に Shift_JIS への変換が発生する場合、XSS が引き起こされる可能性があります。
予約デバイス
U+00A9 U+00D8 U+00D1 (©ØÑ) のような文字列は、Shift_JIS に直すと "CON" という予約デバイス名に変換されます。このような文字列をファイル名として扱うアプリケーションでは DoS を引き起こすことがあります。特に「UTF-8 なファイル名を受け取り、Shift_JIS で保存する」メーラのようなアプリケーションでは注意が必要になります。

ちなみに、前回の記事に対して、ヤマガタさんも「“こんな変換なんて普通しないから大丈夫だよ”と勘違いされてしまいそう」と書かれていますが、勘違いしないでください。これらの「似た文字への変換」は、開発者も知らない暗黙のうちに発生します(なぜなら、前回も書いたようにほとんどのプログラムやミドルウェア、ライブラリなどで WC_NO_BEST_FIT_CHARS を指定せずに WideCharToMultiByte を呼び出しているからです)。
具体的には、argc/argv によるコマンドライン引数の取得時や、ウィンドウテキストやクリップボードの文字列を Ansi バージョンの API を利用して取得した場合、外部DLL呼び出し時の暗黙の変換(VBなど)、IIS の Request("param") によるパラメータの取得、FindFirstFileA を利用したファイルの列挙など…数え上げればキリがありません。

特に、FindFirstFileA を利用したファイルの列挙については、WideCharToMultiByte の説明の "Security Alert"の項には

For strings that require validation, such as file, resource and user names, always use the WC_NO_BEST_FIT_CHARS flag with WideCharToMultiByte. This flag prevents the function from mapping characters to characters that appear similar but have very different semantics.

と書かれているにも関わらず、WC_NO_BEST_FIT_CHARS を指定せずに変換した場合と同じマッピングUnicode のファイル名が Shift_JIS のファイル名に変換されますので、注意が必要です。
次回は、Unicode から ASCII(コードページ1252) への変換についてです。