XSS対策に汚染モードを使う

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/</&lt;/g;
    $str =~ s/>/&gt;/g;
    $str =~ /^(.*)$/s and $str = $1;  # 汚染フラグを落とす。
    return $str;
}

エスケープ漏れがある場合は汚染チェックに引っかかってdieします。

*1:同じような脆弱性の問題でも、SQLインジェクションについてはプレースホルダを使うコーディングスタイルを徹底させることで回避できるので、XSSに比べると人手によるチェックはやりやすい。