0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【セキュリティ】SSTI(Server-Side Template Injection)とは何か —— 仕組み・危険性・実例・防御策まで徹底解説

0
Posted at

はじめに

Webアプリのテンプレートエンジンは、サーバー側で HTML を動的生成するための便利な仕組みです。しかし、そのテンプレート機能が外部入力と誤って結合されると――忍び寄るのが SSTI(Server-Side Template Injection) です。

一見ただのテンプレート構文に見えても、実は「任意コード実行」ができてしまうケースがあり、攻撃者からすると“宝箱”。開発者からすると“恐怖の落とし穴”です。

この記事では、SSTI の 基礎から実例、攻撃の仕組み、防御方法 まで、まとめて理解できるように解説します。

SSTI とは?

SSTI(Server-Side Template Injection)=サーバー側テンプレートへのインジェクション攻撃
テンプレートエンジン(Jinja2、Twig、Freemarker、Velocity など)がユーザー入力を直接レンダリングし、テンプレート構文として解釈されてしまうと発生します。

短く言えば:

「テンプレートエンジンが“実行しちゃダメな文字列”まで実行してしまう脆弱性」

起きる条件

  • サーバー側テンプレートエンジンを使っている
  • ユーザー入力がテンプレートとして評価される
  • 開発者が {value} のように「気軽に埋め込む書き方」をしてしまう

なぜ危険なの? — “RCEの一歩手前”

テンプレートエンジンは、ただの文字置換ツールではありません。
多くのエンジンには 変数・フィルタ・関数・オブジェクト操作 があり、中には Python の任意クラス参照、システムコマンド実行 にアクセスできるものが存在します。

結果として、SSTI は以下を可能にします:

  • 変数値の改ざん
  • サーバー内部情報の取得(PATH、環境変数など)
  • ファイル読み取り
  • 任意コード実行(RCE)
  • サーバー乗っ取り

つまり…

SSTI は「XSS のサーバー版 + RCEのおまけ付き」

と言っても過言ではありません。

典型的な発生例(Jinja2)

NGコード例

return render_template_string("Hello " + user_input)

攻撃者が次のような値を送ると?

{{ 7*7 }}

→ テンプレートエンジンが評価
→ 結果は 49

さらに…

{{ ''.__class__.__mro__[2].__subclasses__()[40]('ls',shell=True,stdout=-1).communicate()[0] }}

→ Python のサブクラスをたどって「subprocess.Popen」へアクセス
ls コマンド実行

こうして RCE が成立します。

他テンプレートエンジンの例

Twig(PHP)

{{ 7*7 }} → 49
{{ constant('PHP_OS') }} → OS 情報

Freemarker(Java)

${"freemarker.template.utility.Execute"?new()("id")}

→ OS コマンド実行

Velocity(Java)

#set($e = ''.getClass().forName('java.lang.Runtime').getRuntime())
$e.exec('id')

どの言語にも存在しているのです。

攻撃者が SSTI を発見する流れ

攻撃者は小さな“注入テスト”から始めます。

Step1:テンプレート構文が効くかを確認

  • {{7*7}}
  • ${7*7}
  • <%= 7 * 7 %>

Step2:エラーメッセージ・レスポンスの変化を見る

  • 計算結果が出る?
  • 例外が変わる?
  • テンプレートエンジン名が漏れる?

Step3:オブジェクト参照ルートを探索

  • Python → MRO ルート
  • Java → メタクラスや Runtime
  • PHP → 定数参照や関数呼び出し

少しずつ“階段を上るように”RCE に近づいてきます。

防御策:実はシンプル

SSTI の防御は「テンプレートにユーザー入力を直接埋めない」これに尽きます。

1. 文字列としてエスケープして扱う

{{ user_input | e }}   # Jinja2 の HTML エスケープ

2. render_template_string を使わない

テンプレートは必ずファイル側で定義。

3. ブラックリストではなく「ホワイトリスト」方式で許可

例:

if username not in allowed_list: reject

4. テンプレートエンジンの sandbox 機能を有効化

  • Jinja2 → SandboxedEnvironment
  • Twig → sandbox extension

5. WAF でテンプレート構文をフィルタする

ただし完全防御は難しいので最後の補強として。

まとめ

SSTI は、シンプルな見た目とは裏腹に 最悪の場合サーバー乗っ取りまで発展する強力な脆弱性 です。
テンプレートエンジンが“便利すぎる”ことが原因であり、開発者はその強力さを理解したうえで安全に扱う必要があります。

  • 入力を直接テンプレートに入れない
  • 必ずエスケープ
  • テンプレートはコードと分離
  • Sandbox を有効化

このあたりを徹底すれば、SSTI に怯える必要はありません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?