(Twitter の XSS 脆弱性に関連して) 構造化テキストの正しいエスケープ手法について
昨日の Twitter の XSS 騒ぎは、まだ皆さんの記憶に新しいことと思います。いい機会なので、ツイートのような構造化テキストのエスケープ手法について触れておきたいと思います。
Twitter のメッセージは、単なる平文(プレインテキスト)ではなく、「@英数字」のような他のユーザーへの言及と「http://〜」のような URL を自動的にハイパーリンク化する構造化テキストです。
このような複数のルールをもつ構造化テキストを HTML 化する際には、どのようなコードを書けばいいのでしょう? まず「@〜」をリンク化してから、URL をリンク化すればいいのでしょうか? それだと、@〜 のをリンク化した A HREF タグの中の URL がさらにリンク化されていまいますね。
では、URL をリンク化してから @〜 をリンク化すればいいのでしょうか? それだと、@ を含む URL があった場合に、やはり HTML が壊れてしまいます。
正しいアプローチは、全てのルールを同時に適用することです。
Perl で書くなら、以下のように、「@〜」と URL を検出するパターンを単一の正規表現にまとめてトークナイズ (split) し、切り出されたトークンがどのタイプかを判定しながら処理していきます。
my $html = '';
for my $token (split m{(http://[0-9A-Za-z_\.\%\?\#\@/]+|\@[0-9A-Za-z]+)}, $tweet) {
if ($token =~ m{^http://}) {
$html .= '<a href="' . encode_entities($token) . '">'
. encode_entities($token) . '</a>';
} elsif ($token =~ m{^\@(.*)$}) {
my $user = $1;
$html .= '<a href="http://twitter.com/' . encode_entities($user) . '">'
. encode_entities($token) . '</a>';
} else {
$html .= encode_entities($token);
}
}
でもルールが複雑になってくると面倒なので... 続きはあとで書く「String::Filter っていうモジュール書いた - 続: (Twitter の XSS 脆弱性に関連して) 構造化テキストの正しいエスケープ手法について」に続く。
Comments