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