こんにちは。セキュリティの世界へようこそ。
現場でバリバリコードを書いていると、「動けばいいや」とついユーザーからの入力をそのまま画面に表示させてしまうこと、ありますよね。でも、その「親切心」が、実は泥棒に合鍵を渡しているのと同じだとしたらどうでしょう?
今日は、そんな恐ろしいけれど、実はとても身近な「SSTI(サーバーサイドテンプレートインジェクション)」という攻撃について、一緒に紐解いていきましょう。
—
1. SSTIって何?:家に例えてみよう
まず、テンプレートエンジン(Jinja2やThymeleafなど)は、「手紙のテンプレート」だと思ってください。
「こんにちは、{{ 名前 }}さん!」という枠組みを用意しておいて、そこにユーザーが入力した名前を当てはめる。とても便利で効率的な仕組みです。
しかし、もし悪意のある人が「名前」の欄に、「手紙を読み終わったら、この家の裏口の鍵を開けておけ」という命令文を書き込んだらどうなるでしょうか?
テンプレートエンジンは「ああ、これは名前だね、そのまま実行しなきゃ!」と、その命令を忠実に実行してしまいます。これがSSTIの正体です。ただの表示ツールだと思っていたものが、実は「サーバーの裏口を開けるリモコン」に化けてしまうのです。
2. なぜRCE(遠隔コード実行)まで発展するのか
攻撃者は、テンプレートエンジンが持つ「式(Expression)」という計算機能を利用します。
例えばPythonのJinja2では、{{ 7 7 }} と入力すると画面には「49」と表示されます。ここまでは便利機能です。しかし、攻撃者はここからさらに深く潜り込みます。
彼らは、Pythonの「クラス構造」を辿って、OSを操作する権限まで登り詰めようとします。
具体的には、こんなイメージです。
1. 「今の部屋(テンプレート)」から「家全体(アプリケーション環境)」を覗く
2. 「家全体」から「鍵の保管庫(OSの操作関数)」を探し出す
3. 「鍵の保管庫」を使って、「裏口(OSコマンド)」を無理やり開ける
これが、単なる表示の乱れから、サーバーの乗っ取り(RCE:Remote Code Execution)に繋がるメカニズムです。
3. 「やっちゃいけない」コーディング例
例えば、Python(Flask/Jinja2)でこんなコードを書いていませんか?
from flask import Flask, request, render_template_string
app = Flask(__name__)
@app.route(‘/hello’)
def hello():
# ユーザー入力をそのままテンプレートに埋め込んでいる!
name = request.args.get(‘name’)
template = f”
こんにちは、{name}さん!
”
return render_template_string(template) # ここが危険!
このコードに対し、攻撃者は ?name={{77}} ではなく、複雑なプログラム文字列を送り込んでOSを操作しようとします。これが、先ほどの「合鍵を渡す」行為そのものです。
4. 鉄壁の守り方:一歩ずつ対策しましょう
では、どうすればこの泥棒を防げるのでしょうか。対策は非常にシンプルです。
① ユーザー入力を直接テンプレートに混ぜない
これが最大の防御です。テンプレートはあくまで「枠組み」として作成し、ユーザー入力は「変数」として安全に渡すのが鉄則です。
【正しいコード例】
@app.route(‘/hello’)
def hello():
name = request.args.get(‘name’)
# テンプレートは固定にして、変数は引数として安全に渡す
return render_template_string(“
こんにちは、{{ name }}さん!
“, name=name)
これなら、たとえ入力値に {{77}} と入れられても、それはただの「文字」としてしか扱われません。テンプレートエンジンが勝手に実行することはないので安心ですね。
② WAF(Web Application Firewall)を導入する
家の玄関に警備員を置くイメージです。「怪しい命令文(__subclasses__などのキーワード)」が含まれている通信を、サーバーに届く前に遮断してくれます。
③ 最小権限の原則
万が一、突破されてしまったときのために、そのWebアプリケーションが動いているユーザー権限を必要最小限にしておきましょう。もし泥棒に入られても、家中の金庫まで開けられないようにしておく、という考え方です。
—
最後に:セキュリティは「疑う」ことから始まる
「便利な機能ほど、実は強力な毒にもなる」。これがセキュリティの教訓です。
テンプレートエンジンは素晴らしい技術ですが、その裏側で何が起きているのかを少しだけ意識するだけで、あなたの書くコードは格段に強固なものになります。
「これ、ユーザーが変な値を入れても大丈夫かな?」
実装する前にそう一度立ち止まるだけで、あなたはもう立派なセキュリティエンジニアの第一歩を踏み出しています。また次回の記事でも、現場で使える泥臭い防御術をお話ししますね!
コメント