Server-Side Template Injection(SSTI)完全ガイド:仕組み・実例・攻撃方法・防御策
SSTI(サーバーサイドテンプレートインジェクション)は、Webアプリケーションのテンプレートエンジンがユーザー入力を処理する際に生じる、危険な脆弱性です。適切な入力フィルタがなければ、攻撃者はテンプレート構文を注入して、任意のコード実行、データ漏洩、サーバー乗っ取りを実行できます。この記事では、SSTIの正体と攻撃例、防止策を徹底解説します。
「テンプレートはHTMLを作るだけ? いいえ、SSTIが仕掛けられていれば、あなたのサーバーはハッカーの遊び場になります。」
🧩 SSTIとは何か?
SSTI(Server-Side Template Injection)とは、サーバー側テンプレートエンジンが、ユーザー入力をテンプレートとして評価してしまうことにより発生する脆弱性です。攻撃者はテンプレート構文(例:{{…}} や ${…})を注入し、任意のコード実行を行うことができます。
🧠 どのように悪用されるのか?
以下のような状況があると、SSTIのリスクが発生します:
- テンプレートに直接ユーザー入力が埋め込まれている
- テンプレートエンジンが動的に評価される
- 開発者が{{ user_input }}のような形式で出力している
💥 結果:攻撃者は {{ 7*7 }} → 49 といった構文を注入し、テンプレートエンジンでコードを実行させられる可能性があります。
🧪 テンプレートエンジン別のSSTI例
テンプレートエンジン | インジェクション構文 |
---|---|
Jinja2 (Python) | {{ 7*7 }} |
Twig (PHP) | {{ dump(app) }} |
Velocity (Java) | ${7*7} |
Smarty (PHP) | {$smarty.version} |
👨💻 ハッカーの攻撃シナリオ
- ユーザー入力フィールドを見つける(例:メッセージ投稿欄)
- {{7*7}} のような構文を試す
- 出力が 49 であればテンプレートが評価されていることを確認
- 次にファイル読み込みやRCE(リモートコード実行)を狙う構文を試す
{{ config.__class__.__init__.__globals__['os'].popen('ls').read() }}
このような構文が通れば、サーバー内部のディレクトリ情報が取得されてしまいます。これは完全にシステム乗っ取りの入り口です。
☠️ SSTIの危険性
- 💀 任意コード実行(RCE)に直結
- 🔓 セッション情報・認証トークンの漏洩
- 🧨 データベースのダンプやユーザー情報の取得
- 📂 任意ファイルアクセス、リモートシェルの挿入
「SSTIは、XSSやSQLインジェクションを遥かに超える危険性を持ちます。RCE=ゲームオーバーです。」
🛠️ 実装例:脆弱な vs 安全なコード
❌ 脆弱な例(Python Flask + Jinja2)
@app.route('/greet')
def greet():
name = request.args.get('name')
return render_template_string("Hello {{ %s }}" % name)
✅ 安全な例
@app.route('/greet')
def greet():
name = request.args.get('name')
return render_template("hello.html", name=name)
テンプレートファイルとロジックを分離し、render_template_string のような動的テンプレート評価は避けましょう。
🛡️ SSTIの防止方法
- 🔒 テンプレートに直接ユーザー入力を入れない
- 🧼 テンプレート文字列を事前にフィルタ・サニタイズ
- 👨💻 テンプレートエンジンの設定で評価関数を無効化
- 🛑 render_template_stringを避ける
- 🧪 セキュリティスキャナで自動チェック(Burp Suiteなど)
📌 まとめ:テンプレート処理=コード実行の可能性
SSTIは、テンプレートの中に“コード”を仕込むことで発動する攻撃です。もしサーバー側でテンプレート評価を動的にしているなら、今すぐその実装を見直しましょう。テンプレートは見た目だけではありません。評価対象にしてしまえば、あなたのシステムそのものが侵入の足がかりになります。
「ユーザーが見ているHTMLの裏側に、攻撃者のコードが動いているとしたら? それがSSTIの本質です。」