UTF-7エンコードの特性を利用したクロスサイト・スクリプティング(UTF-7 XSS)を紹介します。この攻撃はブラウザが出力をUTF-7として認識した場合に生じるものです。日本ではUTF-7は一般的ではありません。しかし、プログラマはこういった文字コードとXSSの関係を把握しておくべきでしょう。

まずは、ブラウザが出力をUTF-7と解釈した場合にJavaScriptが実行されてしまうことを確認しましょう。次のコードをUTF-8等の文字コードで保存し、ブラウザから開いて下さい。

<?php
mb_internal_encoding
('UTF-8');
$str "<script>alert('XSS');</script>";
$str mb_convert_encoding
($str'UTF-7');

header("Content-Type: text/html; charset=UTF-7");
echo 
htmlentities($str);
?>

JavaScriptが実行され、アラートでXSSと表示されたと思います。htmlentities()を用いてエスケープ処理をしているにも関わらず、なぜこのようなことが起こるのでしょうか?

その原因は、エスケープ処理をされる文字列のエンコードとブラウザが解釈する文字コード間にズレが生じていることにあります。

まず、出力文字のエンコードですが、コード中で文字列をUTF-7に変換していることに注意して下さい。変換された『<script> alert('XSS');</script>』をUTF-8で出力すると『+ADw-script+AD4-alert('XSS')+ ADsAPA-/script+AD4-』という文字列になります。htmlentities()はこの文字列をUTF-7とは認識していない為にどの部分も変換しません。

しかし、実際にこの文字列がUTF-7と認識された場合、『+ADw-』と『+AD4-』はそれぞれ『<』と『>』と解釈されます。上述のコードでは、header()関数を用いてブラウザに対して文字エンコーディングをUTF-7で指定しています。その為にブラウザは文字列『+ADw- script+AD4-alert('XSS')+ADsAPA-/script+AD4-』を『<script>alert('XSS');</script>』と解釈し、Javascriptを実行してしまいます。

このようなUTF-7 XSSが成立する為には、ブラウザの文字エンコーディングを変更させる必要があります。実際には、PHP内のheaderやHTMLのmetaタグ内で文字セットを指定する部分にユーザ入力が入っていなければ問題にはならないでしょう。

しかしながら、文字コードによってはhtmlentities()等のエスケープ関数でも対応できない場合が存在することを覚えておいて下さい。


(アシアル 井川数志)

この記事は、アシアルが運営するPHP開発者のためのポータル&コミュニティサイト「PHPプロ!」で毎週配信しているPHP・TIPSメーリングリストを再録したものです。
同サイトでは、他にもPHP最新ニュースや、困ったときのQ&A掲示板、初心者向けのPHP講座など、PHP開発者をサポートする情報を掲載しています。