与えられたURLをどう扱うか

朝顔日記rNote の微改造とかについて、先方の掲示板に意見を書いたのですが、続・rNote の微改造とかでの改造のしかたを見ると、自分の意見の後半部分(以下に引用)がうまく伝わっていないようだったので、具体例を使って補足説明したいと思います。

それはともかくとしても、外部からURL文字列を渡される場合は、(送り手側がHTML向けのエスケープを施したURLなどでなく)何も変換していない「ありのまま」のURL文字列が渡されるはずなので、HTML / XHTMLで使う時には、単に全ての"&"を"&"に変換しておけばいいように思います。

例えば、

というURLがあるとします(さっき作りました)。このページから続・rNote の微改造とかへリンクを張り、誰かがそのリンクを辿ると、朝顔日記で動作しているアプリケーション(rNote)はこの http://www.akatsukinishisu.net/wiki.cgi?& というURLを記録して保存します。

さて、このURLをrNoteが「リンク元」として表示する場合、"&" という文字はHTMLでは単体では使えない文字なので、"&"という実体参照に置き換える必要があります。この処理は具体的には続・rNote の微改造とかに載っているソースの2行目にあたり、これによりリンク元として記録されたURLは、

という文字列に置き換えられます。

しかし、続・rNote の微改造とかのソースを見ると、3行目に

$a = preg_replace("/&/","&",$a);

という変換処理があります。この変換が施されると、元のURLは更に

という文字列に置き換えられることになります。

そして、このURLがHTMLソースとして出力されると、最終的に我々がブラウザを通して見るURLは、

という物になります。これは元のURLとは変わってしまっています。

要するに、続・rNote の微改造とかのソースの3~6行目のような処理があると、「元々"&"という文字列を含んでいたURLさえも"&"に改変してしまう」おそれがあるため、そのような処理はすべきではないと考える次第です。また、それなので掲示板では「HTML / XHTMLで使う時には、単に全ての"&"を"&"に変換しておけばいいように思います」(⇒それ以上の処理は必要無い)ということを述べた訳です。

* * *

以上のことは「XHTMLでパースエラーを出さないようにする」というのりさんの当初の目的とはやや方向性の異なる、「与えられたデータをいかに正しく保つか」といった意見ではありますが、実際XHTMLでパースエラーを出さないことを考えた場合でも、やはり"&"を"&"にするだけで十分かと思います。

また、"&"を単独で使うとXHTMLやXMLでは明確にエラーとなりますが、実のところHTMLでだって単独で"&"が現れるのは文法違反です。なのでその辺りは本家rNoteでも修正された方がよいように思います。

あとそれとは別に、リンク元URL(Referer)のように外部からデータを渡される際には、危険な文字列(HTMLでは"<"、">"とか)を渡されたら無効化サニタイズすることも重要となります。自分がrNote 0.9.7.5を試しに使ってみた限りでは、どうもRefererに対してはサニタイズが考慮されていない様子だったので、その辺も修正が必要であるかもです。