UTF-8 での注意点
非最小形式の不正なエンコーディングに注意
UTF-8 は文字によって1文字あたりのバイト数が1バイトから4バイト(もしくは6バイト)と可変長なエンコーディングです。Unicode の各文字がどのようなバイト列で表現されるかは、下表のようになっています。
Unicode 文字範囲 | UTF-8 でのバイト列(2進数) |
---|---|
U+0000〜U+007F | 0xxxxxxx |
U+0080〜U+07FF | 110xxxxx 10xxxxxx |
U+0800〜U+FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
U+10000〜U+10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
ところが、意図的に必要以上のバイト数で文字を表現することにより、文字列のチェックをすり抜けられる可能性があります。例えば、スラッシュ / (U+002F) は、本来ならば UTF-8 での表現は 0x2F となりますが、無理矢理 2バイトで表現した場合、0xC0 0xAF となりますし、3バイトで表現した場合には 0xE0 0x80 0xAF となります。
このように、必要以上に長いバイト数を使って UTF-8 を構成することにより、単純なバイト列の比較をすり抜けられる可能性があります。この問題は、"Unicode Web Traversal" や "Path Traversal" などと呼ばれ、実際に CodeRed などでも攻撃に利用されました。
また、同じように、ヌル文字 \0 (U+0000) は、UTF-8 での正しい表現は1バイトの 0x00 ですが、2バイトで 0xC0 0x80 と表現したり、3バイトで 0xE0 0x80 0x80 と表現することができます。もし、これらを UTF-8 として受け入れてしまった場合、バイト列が 0x00 で終端していないため、使用しているライブラリなどにおいてバッファオーバーフローを引き起こす可能性が高まります。
UTF-8においては、最小形式以外の冗長なバイト列は、文字列として受け入れてはいけません。
ISO/IEC 10646 の文字範囲では、最大6バイト
Unicode での文字範囲は U+0000〜U+10FFFF に納まり、そのため UTF-8 では最大4バイトとなりますが、Unicode とは兄弟のような規格である ISO/IEC 10646 においては、文字の範囲は U+7FFFFFFF までとなり、そのため UTF-8 の最大長は6バイトになることがあります。
もしU+10FFFF を超える文字を許容するのであれば、必要なバッファのサイズは、最大文字数×4バイトよりも多くなることもありますので、バッファオーバーフローを引き起こさないように注意が必要です。