【入門編】テンプレートインジェクション(SSTI)のメカニズム – アプリケーションセキュリティ & 安全な開発防御ガイド

「テンプレート」が裏切る瞬間:SSTIという名の「招かれざる訪問者」

こんにちは。セキュリティの現場で長年、泥臭いインシデント対応や防御策の設計をしてきた者です。

今日は、開発現場で意外と見落とされがちな、しかし一度侵入されると致命的な「SSTI(サーバーサイドテンプレートインジェクション)」についてお話しします。難しそうな名前ですが、身近な例えで紐解いていきましょう。

1. SSTIって、結局なに?(泥棒の例え)

想像してみてください。あなたは自分の家(サーバー)に、「自動手紙作成ロボット(テンプレートエンジン)」を置いています。

このロボットは優秀です。あなたが「親愛なる{{名前}}様」と書けば、{{名前}}の部分を「山田さん」や「佐藤さん」に自動で書き換えて手紙を仕上げてくれます。

しかし、もしこのロボットが「手紙の本文に何が書かれていても、そのまま実行してしまう」というお調子者だったらどうでしょう?

悪意のある泥棒が、{{名前}}の場所に「名前」ではなく、「家の合鍵を作って、裏口を全開にしておけ」という命令文を書き込んだら……。ロボットはそれを「あ、新しい指示ですね!」と受け取り、あなたの家のセキュリティを無効化してしまいます。

これがSSTIの正体です。「表示するための枠組み(テンプレート)」に、「命令文(コード)」を紛れ込ませて、サーバーに実行させてしまう攻撃なのです。

2. なぜ「Jinja2」や「FreeMarker」が狙われるのか

Jinja2(Python)やFreeMarker(Java)のようなテンプレートエンジンは、本来「ユーザーの入力内容を安全に表示する」ために使われます。しかし、便利さの代償として、これらはプログラミング言語の深い機能(クラスを辿ったり、システムコマンドを呼び出したり)にアクセスできるパワーを持っています。

開発者が「ここには名前が入るはずだから大丈夫だろう」と油断して、ユーザー入力をそのままテンプレートとして読み込ませてしまうと、攻撃者はそのパワーを悪用し、サーバーの裏側(RCE:リモートコード実行)まで手を伸ばしてくるのです。

3. ダメな例と、安全な例を見てみよう

たとえば、PythonのWebフレームワークであるFlask(Jinja2)を使った、こんな「やってはいけないコード」を想像してください。

from flask import Flask, request, render_template_string

app = Flask(__name__)

【危険なコード】ユーザーの入力をそのままテンプレートとして処理している
@app.route(“/hello”)
def hello():
user_name = request.args.get(‘name’)
# ユーザー入力がテンプレートの一部として解釈されてしまう!
template = f”

こんにちは、{user_name}さん!

”
return render_template_string(template)

このコードに、もし攻撃者が ?name={{77}} と入力したらどうなるでしょう? ブラウザには「こんにちは、49さん!」と表示されます。計算が実行されてしまった証拠です。これがさらに巧妙になると、サーバー内のファイルを盗み出したり、ネットワークを乗っ取ったりするコマンドにすり替わります。

どう直せばいいの?

答えはシンプルです。「入力値はテンプレートに直接埋め込まず、変数を介して渡す」、これに尽きます。

【安全なコード】テンプレートの「枠」は固定し、値を「変数」として渡す
@app.route(“/hello”)
def hello():
user_name = request.args.get(‘name’)
# テンプレートは固定文字列にする
template = “

こんにちは、{{ name }}さん!

”
# 変数として渡せば、テンプレートエンジンは「ただの文字」として扱う
return render_template_string(template, name=user_name)

これなら、もし誰かが {{77}} と入力しても、画面にはそのまま {{77}} と表示されるだけで、計算が実行されることはありません。これが「入力と命令を分ける」という防御の基本です。

4. 現場で意識すべき3つの防衛線

1. 「テンプレート文字列」を動的に作らない
上記の例のように、ユーザー入力を使って render_template_string の引数を組み立てるのは絶対にNGです。テンプレートファイル(.htmlなど)として静的に管理しましょう。
2. テンプレートエンジンを最新に保つ
ライブラリ側でも、予期せぬ実行を防ぐためのアップデートが日々行われています。脆弱性情報は常にチェックしましょう。
3. 最小権限の原則
万が一、攻撃者にコマンドを実行されてしまったとしても、被害を最小限にするために、Webアプリケーションは「root権限」などの強い権限で動かしてはいけません。

最後に:セキュリティは「疑う」ことから始まる

「こんな簡単なこと、誰も悪用しないだろう」という甘い考えこそが、攻撃者にとっての扉の鍵になります。

セキュリティは、魔法のようなツールを入れて終わりではありません。「自分の書いたこのコードが、もし悪い心を持った人に触られたらどう動くか?」という想像力を働かせること。それこそが、エンジニアとして一番の武器になります。

今日から、テンプレートエンジンの使い方を少しだけ立ち止まって見直してみませんか? 一歩ずつ、あなたの書くコードをより強固にしていきましょう。応援しています!

コメント

タイトルとURLをコピーしました