対策遅らせるHTMLエンコーディングの「神話」:ITpro

はてブ

「すべてをエンコードすると決めた」といいながらメタキャラクタしかエスケープしないのはなぜ?

と書いたら、b:id:HiromitsuTakagi さんに

/↓hasegawayosuke「なぜ」<意味不明 /

言われてしまいますた
全ての文字をエスケープしようなどと非現実的なことは言わないけれど(とはいえMicrosoft Anti-Cross Site Scripting Libraryのようにほとんど全ての文字を実体参照に置き換えるものもあるので、あながち非現実的とも言えないのかも知れない)、エスケープ対象を「'」「"」「<」「>」「&」の5文字に限定しているのは何かこの記事に書かれていない理由があるはずだと思ったからです。
この5文字さえ確実にエスケープしていれば XSS が防げるかというと、多分そうでもないだろうと個人的には思うわけでして。
例えば IE ではバッククォート「`」(U+0060)が引用符と同じように使用できますので

<input type=text value=``onmouseover=alert(document.domain)>

のようなHTMLでもスクリプトが動きます。もちろん、属性値を引用符で囲んでいないのが最大の原因で、こういった例はあまり実在しないことは承知していますが、

アプリケーションの要件から見てエンコードが不要なフィールドまでHTMLエンコードするのは無駄に思えるかもしれないが,そうではない。HTMLエンコードに要する労力はわずかなものだし,すべての項目をエンコードすることによりチェックなどが容易になる。すべてをエンコードすると決めたほうが簡明でミスが少なくなるわけだ。逆に,ある部分はエンコードし,別の部分はエンコードしないという状態になると,かえって煩わしい。

と書かれているように、どうせならもっと積極的にエスケープすればよいのに、と思ったのでした。

以下はおまけ。IEでは innerHTML を取得した時点で属性値の前後の引用符が消えるため、スクリプトの注入ができます。

<div id="div1">
  <input type="text" value="``onmouseover=alert(document.domain)">
</div>
<div id="div2"></div>
<script>
    document.getElementById("div2").innerHTML =
      document.getElementById("div1").innerHTML;
</script>