ActixWeb にパッチを送った話
はじめに
先日、ActixWeb にパッチを送りました。とは言っても本体ではなく examples の中に格納されている todo アプリの話。
本記事では僕がなぜこのパッチを送る事になったのか、どうやってこの todo アプリのバグを見つけたのか、を紹介したいと思います。技術的な話はほぼありません。
どうやって見つけたのか
僕はウェブアプリを試す時に そのアプリが信用できる物かどうか を確認する意味で <script>alert(1)</script> といった XSS なコードを入力ボックスに埋め込む事をよくやります。悪意はありません。これは自衛です。おそらくエンジニアの方であれば皆やると思います。(え、やらない、そうですか)
とは言っても最近はテンプレートエンジンを使うのが当たり前になってきていて、そのまま alert が表示される事はほぼなくなりました。そして最近では XSS を作ってしまう方が恥ずかしいレベルになってきています。そんな中、先日試した ActixWeb の examples/todo は見事に alert が表示されてしまったのです。
しかしソースコードを見ても Rust のテンプレートエンジン Tera をちゃんと使っている。まさか最近のテンプレートエンジンでデフォルトで HTML をエスケープしない物なんかある訳ないだろうと思い一旦は「もしかしてこれヤバい物を見つけてしまったんじゃないか」とすら考えました。
なにが問題だったのか
ここで Tera がどうやって HTML をエスケープしているかを見てみましょう。Tera がテンプレートエンジンの中で値を評価しているのは src/renderer/processor.rs の eval_expression です。
        if self.should_escape && needs_escape && res.is_string() && !expr.is_marked_safe() {
            res = Cow::Owned(
                to_value(self.tera.get_escape_fn()(res.as_str().unwrap())).map_err(Error::json)?,
            );
        }
この should_escape は Processor のコンストラクタ new で渡されます。そしてこの should_escape は autoescape_suffix から作られます。
autoescape_suffix のデフォルト値は .html と .htm と .xml です。おや、ドットが含まれていますね。そう、Tera はファイルタイプではなく拡張子で autoescape_on を指定するのです。たしか todo アプリのソースで使われているテンプレートファイルの拡張子は .html.tera でした。
となれば .tera もエスケープ対象にしないといけませんよね。
修正した内容
本来、Tera の思想は拡張子 .html なファイルを扱うので、autoescape_on を使って拡張子 .tera をエスケープ対象に設定してやります。
これでようやく XSS せずに入力される様になりました。
ところで
Tera は自動でエスケープすると思っておられる方が結構いる様で GitHub には .html.tera というファイル名を使っておられる方がたくさんおられます。
ぜひお気を付けください。そして autoescape_on を使う様に、もしくはテンプレートの中で {{ value | escape }} を使うよう、教えてあげて下さい。
さもないと alert(1) が表示されてしまいますよ。
Discussion