2007-08-29 TwitterのXSS対策は変だ
● Twitterのクロスサイト・スクリプティング(XSS)対策は変だ
Twitterが流行している。私もヘビーユーザとは言えないものの、結構愛用している(http://twitter.com/ockeghem)。このTwitterのXSS対策が変だなと思う事象があったので報告する。
あらかじめお断りしておくが、TwitterにXSS脆弱性がある(実際にはあったようだが)という報告ではなく、対策の方法がおかしいという報告である。
まずは、どうも変だと思うようになった事例を紹介する。
事例1 モバイル版の二重エスケイプ
私は主に、通勤などの移動中に、W-Zero3で閲覧・書き込みしている。モバイル版(http://m.twitter.com/)を主に利用しているが、「<」などの記号が二重にエスケープされていることに気がついた。
twitter.comでの表示

m.twitter.comでの表示

事例2 検索画面が変
「Find&Invite」という機能でお友達候補を検索できるのだが、この機能が変だ。「lt」という単語で検索すると、「<」がヒットする。検索結果の例を下図に示す(私のプロファイル)。

しかしこの表示は実はおかしくて、私のプロファイルは実際には下図のように設定されているのだ。

すなわち、ltで検索すると、「<」がヒットされていることになる。そして、ネタばれのように、検索結果表示では「<」の部分が「<」と表示される。
3.事例3 文字数制限が変
Twitterの氏名欄(Full Name)は20文字までという制限になっているが、「<」などの文字を使うと、より少ない文字しか入らない。ここで、「<1234567890123>」という15文字の名前を入れてみる。
すると、下図のように、「<1234567890123>」というように文字列が化けてしまう。

おそらく、内部的には「<1234567890123>」と格納しようとしたものの、これだと21文字になるので、末尾のセミコロンが削除されてしまったのだろう。
結論:Twitterは、HTMLエスケープされた状態で情報を保存している
もういいだろう。ソースを確認したわけではないが、これだけ状況証拠があれば十分だ。TwitterはHTMLエスケープされた文字列をDBに保存していることは間違いない。しかし、この方法は間違っている。HTML表示する直前にHTMLエスケープするという原則に反しているからだが、その結果として、上記に見るような悪影響が出ている。設計ミスというほかないだろう。
さて、文字列をHTMLエスケープされた状態で保存したために悪影響が出ていることは報告の通りだが、この方法のメリットはあるだろうか?一つ思いつくことは、DB格納の段階でまとめてHTMLエスケープすることにより、HTMLのエスケープもれによるXSS脆弱性が発生することを防ぎたかったのかもしれない。
しかしながら、この方法ではかえってXSS脆弱性を招きやすいと私は思う。DBの値はエスケープ済みだが、画面からの入力値(などDB以外の値)はエスケープされていない。両者が混在することによって、エスケープすべきものとしなくてよいものの区別が煩雑になり、結果としてXSS脆弱性が発生しやすくなると思われる。現実問題、TwitterではXSS脆弱性が報告されているようである。
TwitterのXSS対策はサニタイズではなくエスケープという正しい方法を使っているが、エスケープする場所がよくなかった。Twitterそのものの改良も期待するが、読者が抱えるプロジェクトのセキュリティ対策の参考になれば幸いである。
追記(2007/08/29 19:30)
<と>以外の記号について調べると、「&」、「"」、「'」については何もエスケープされていないことが分かった。ひどい仕様だ。このため、画面から「<」と入力すると、これらの記号はそのままDBに入り、そのまま表示されるので、「<」に文字化けする。その他、XSSになりそうな爆弾もありそうだ。
twitter.comのようなアドホックなXSS対策は見たことがなく、ある意味興味深い。
[]
& のエスケープですが、HTMLの文字参照になっている場合はエスケープしないという仕様のようです。&foo; とかすると &foo; になります。「"」「'」についてはブログなどの本文部分でも(tDiaryでも)エスケープしないのが普通じゃないでしょうか? twitter の仕様として妥当かどうかは疑問ですけど…
rnaさん、ツッコミありがとうございます。&のエスケープの件、ありがとうございます。そういうことですか。しかし、一貫性がなくて表示がおかしくなる点は問題ですよね。「'」と「"」は、属性値もエスケープされていない箇所がありまして、あやうくXSSかという感じです。