flawopen.com/SSTI/解説
サーバーサイドテンプレートインジェクションとは?
サーバーサイドテンプレートインジェクションは、信頼できない入力をデータとして渡さず、テンプレートソースとして解析させることで発生します。影響はエンジン、設定、公開された機能に依存し、式の評価からサーバー側コード実行まで幅があります。すべての SSTI がコード実行につながるわけではありません。
# Python / Jinja2 template = f"Hello {name}!" return render_template_string(template) # Input: {{ 7*7 }} renders as "49" # This confirms expression evaluation; # impact still depends on engine access. // Java / Freemarker String tpl = "Welcome " + userName; new Template("t", tpl, cfg) .process(model, out);
# The template is a fixed string the # developer wrote. The user value is # passed in as a variable. return render_template( "greeting.html", name=name ) # Or with a literal template string: return render_template_string( "Hello {{ name }}!", name=name ) // Java equivalent: template from file, // user value in the model map.
重要な違い
テンプレートエンジンの入力はテンプレートとコンテキストデータの二種類です。テンプレートはプログラムであり、データはそのプログラムが読む値です。SSTI はユーザー入力をデータからテンプレートソースへ越境させることで起こります。
これはデータをクエリ文字列に連結する SQL インジェクションと同じ構造上の誤りです。また、ログを経由してデータが式評価器に届いた Log4Shell とも同様です。対策の原則は共通で、プログラムを固定し、信頼できない値をパラメーターとして渡します。
コード実行に至る可能性がある条件
テンプレートエンジンが強力なオブジェクトやメソッドを公開すると、攻撃者がアプリケーションの機密機能に到達する可能性があります。コード実行の可否はエンジン、バージョン、設定、サンドボックス、公開データに依存します。情報漏えいやリソース枯渇もあり得ます。ユーザー制御のテンプレートソースはアクティブなロジックとして扱い、アクセス可能なオブジェクトや描画リソースを制限せずにサンドボックスだけに依存しないでください。
検出方法
{{7*7}}
${7*7}
<%= 7*7 %>
#{7*7}
応答にリテラル文字列ではなく 49 が含まれる場合、入力がテンプレート構文として評価されています。短い算術式は許可されたテスト環境で評価の有無を調べるのに役立ちます。構文はエンジンごとに異なり、それだけで確実な特定はできません。
よくある質問
いいえ。クライアント側テンプレートインジェクションは被害者のブラウザーで実行され、XSS の一種となる場合があります。SSTI はサーバー上のアプリケーションプロセスで評価されます。影響はエンジンと公開機能によって異なり、一部の設定ではコード実行が可能ですが、すべての SSTI で自動的に起きるわけではありません。
いいえ。自動エスケープは描画される値を処理しますが、値がテンプレート構文として解析されることは防ぎません。出力時の XSS 対策であり、テンプレートソースへの注入対策ではありません。
ユーザー提供のテンプレートソースを実行ロジックとして扱い、既定ではアプリケーションの主要コンテキストで処理しないでください。必要な場合は制限されたテンプレート向けのエンジンを使い、最小限の不活性データだけを公開して、CPU、メモリー、出力サイズ、時間を制限します。サンドボックスだけでは完全なセキュリティ境界になりません。
参考資料
- CWE-1336 — Improper Neutralization of Special Elements Used in a Template Engine
- PortSwigger Web Security Academy — server-side template injection
- OWASP Testing Guide — testing for SSTI
- Is Jinja2's render_template_string() safe?
- Are Freemarker and Velocity templates safe with user input?
- Jinja documentation — Sandbox security considerations