XSS対策の基本は、信頼できない入力をすべてチェックし、出力時に正しくエスケープすることにつきる。そんなことわかっているのにXSSが発生してしまうのは、エスケープ漏れを機械的に判別する方法がない(すなわち人手によるレビューに頼っている)から。*1
Perlにはご存知のように「汚染モード」というものがあります。これをXSS対策に使ってみようというお話。
まず、HTMLをprint文でばらばらに出力するのをやめます。具体的には、HTMLを組み立てる変数を用意して、1度にprint文で出力するようにします。で、printする直前にこの変数の汚染チェックをすればOK。
my $html; # HTML組み立て用変数 $html .= ... # printせずに変数に追加。 ... { my $x = $html, kill 0; } # 汚染チェック。 print $html; # HTML出力。
あとは、エスケープする関数で汚染フラグを取り除けばよい。
sub html_escape { my ($str) = @_; $str =~ s/&/&/g; $str =~ s/"/"/g; $str =~ s/</</g; $str =~ s/>/>/g; $str =~ /^(.*)$/s and $str = $1; # 汚染フラグを落とす。 return $str; }
エスケープ漏れがある場合は汚染チェックに引っかかってdieします。
*1:同じような脆弱性の問題でも、SQLインジェクションについてはプレースホルダを使うコーディングスタイルを徹底させることで回避できるので、XSSに比べると人手によるチェックはやりやすい。