文字列の正規化

4種類の正規化方法

Unicode では、文字の分解や合成、よく似た文字などのために、見かけが同じ文字列でも、バイト列としては複数の表現が可能となっています。そこで、文字列の検索などを行いやすくするために、Unicode では、以下の4種類の正規化方法が規定されています。

  • NFC - 正規合成
  • NFD - 正規分解
  • NFKC - 正規互換合成
  • NFKD - 正規互換分解

検索する文字列および検索対象の双方を、上記のいずれかの方法で正規化したのちにバイト列の比較を行うことにより、文字列を正しく検索することができます。
ただし、これらの正規化は、一方通行であるため、正規化した文字列から、もとの正規化されていない文字列を復元することは不可能ですので、注意が必要です。

正規化により変化する文字に注意

正規化することにより、文字列が危険なバイト列に変化することがある点にも注意が必要です。
例えば、 は、NFKD および NFKC で正規化することにより、.. すなわち、".." という上位ディレクトリを表すバイト列に変化します。
また、 も、NFKC、NFKD によって 1 に変換されます。
処理系の各層の途中で文字列の正規化がなされる可能性がある場合には、正規化後の文字列が危険ではないかにも注意を払わなければなりません。

まとめ

これまで述べてきたように、Unicode を使用するシステムでセキュアな実装を行うのは簡単ではありません。
以下に、注意点をまとめておきます。

各層での文字の扱いを把握・統一する
文字列を検査するライブラリ関数などと、ファイルシステムやデータベースなどでの文字列の扱いに差異がないようにしましょう。
最終的に利用される文字コードに変換したときのことを意識する
内部コードとしてUnicodeを使用するのであれば、最終的に非Unicodeに変換された時点で、害を与える文字列に変換されないように意識しましょう。
危険な文字列の検出ではなく、安全な文字列との一致を検査する
デフォルトセキュアの原則に従い、入力された文字列に危険な文字列を含んでいないかを検査するのではなく、入力された文字列が安全かどうかを検査するような実装にしましょう。

これらは、あくまでも最低限守るべきラインであり、実際の実装においてはより慎重にコーディングを進める必要があるのではないかと思います。Unicode が必ずしも必要というわけではないアプリケーションならば、Shift_JISEUC-JP を利用するというのも、セキュアな実装へのひとつの手段かも知れません。

長々と述べてきましたが、間違いや不明点、提案その他がありましたら、是非 openmyaML に投げていただければ幸いです。

(終り)