Edited at

Ktor の FreeMarker で auto-escaping を有効にする

More than 1 year has passed since last update.


Auto-escaping

テンプレートエンジンを使用している場合に、データベース等から取り出した値を展開させることは多々あると思いますが、エスケープが漏れていてはXSSなどに悪用される危険性があるため、自動でエスケープしてくれると安心です。

FreeMarker には auto-escaping という機能があります。

これは、${name}などのテンプレート部分を展開する際に、テンプレートファイルの拡張子から出力ファイル形式を推測して自動的にエスケープを行う機能です。

FreeMarker のドキュメントによると、HTML形式で出力したい場合には .ftlh 、XML形式で出力したい場合は .ftlx を拡張子に利用することが推奨されており1、これらを利用することで auto-escaping を利用することができるようです。

auto-escaping を使用しなくても ${name?html} のように escape することはできますが、万が一忘れていれば大変ですし、こちらは auto-escaping がデフォルト設定で有効になった 2.3.24 以降では deprecate されています。


Ktor FreeMarker Feature

Kotlin 製サーバアプリケーションフレームワークの Ktor には標準で FreeMarker をサポートする Feature (プラグインのようなもの)があります。

この記事を執筆している2017年12月現在ではバージョン [2.3.20, 2.4) の範囲のものを利用するようになっているようです。

手元で確認したところ、 2.3.27-incubating が利用されていました。


auto-escaping を有効にする

2.3.27 が使用されているということは、一見 auto-escaping が有効かのように見えます。

先述の通り HTML 形式の出力であることを明確にするためには .ftlh という拡張子を使用すればよさそうです。

しかし、実際これでは auto-escaping は有効になりませんでした。

FreeMarker Feature のソースコード2を見ると、 FreeMarker の Configuration に Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS で定義されたバージョンが使用されていることがわかります。

この定数は 2.3.0 を指しているため、そのままでは auto-escaping が利用できなかったのです。

auto-escaping を明示的に有効にするには、 Configuration の recognizeStandardFileExtensions を true に設定します。

install(FreeMarker) {

// ...
recognizeStandardFileExtensions = true // enable auto escaping
}

この設定を行うことで、 .ftlh という拡張子がついたテンプレートファイルは HTML 形式として出力されることが明確になり、 FreeMarker は変数展開時に auto-escaping を行ってくれるようになります。