サーバサイドテンプレートインジェクションとは?起きるパターンと対策法

サーバサイドテンプレートインジェクションとは?起きるパターンと対策法

#セキュリティ#Web開発#脆弱性対策

サーバサイドテンプレートインジェクション(SSTI)は、テンプレートエンジンの表現力を攻撃者に握られ、リモートコード実行にまで至る脆弱性です。 対策の勘所は、ユーザー入力をテンプレートの構文ではなく変数として扱えているかどうかです。

サーバサイドテンプレートインジェクションとは

サーバサイドテンプレートインジェクション(SSTI):ユーザー入力をテンプレート文字列の一部として評価してしまうことで、攻撃者がテンプレートエンジンの構文を注入し、任意の処理を実行できる脆弱性です。 入力を埋め込んだ文字列をテンプレートとしてコンパイルする設計が根本原因になります。

多くのテンプレートエンジンはオブジェクトのメソッドや属性にアクセスできるため、{{7*7}}のような式が評価される時点で危険です。 そこからクラスやランタイムをたどられ、最終的にサーバ上でのコード実行(RCE)や情報漏洩に至ります。 XSSが利用者のブラウザ上で完結するのに対し、SSTIはサーバ側で評価されるため、被害はサーバの掌握にまで及びます。

サーバサイドテンプレートインジェクションが起きるパターン

典型的な混入箇所は次のとおりです。

  • ユーザー入力を連結した文字列を、テンプレートとしてコンパイルして描画している(render_template_string(input)など)
  • メール本文や通知の文面をテンプレートで管理し、その中にユーザー由来の値を構文ごと差し込んでいる
  • 管理画面などでテンプレート自体をユーザーに編集させ、サンドボックスなしで評価している
  • 表示用のフォーマット文字列にユーザー入力を使い、エンジンがそれを式として解釈している

共通するのは「入力が値としてではなく、テンプレートの構文として評価される経路がある」という点です。

対策法

原則は「ユーザー入力はテンプレートの構文に混ぜず、あらかじめ定義したテンプレートへ変数として渡す」ことです。

  • テンプレートは固定の文字列として持ち、ユーザー入力は変数(コンテキスト)として引き渡す。文字列連結でテンプレートを組まない。これが本命の対策になる
  • ユーザーに文面を編集させる必要があるなら、式を評価できないロジックレステンプレートを使う
  • どうしても評価が必要なら、サンドボックス環境で許可した機能だけに制限する
  • テンプレートエンジンの権限やアクセスできるオブジェクトを最小化する(被害軽減策)

入力のフィルタリングでメタ文字を弾く方法はエンジンごとに抜け道があり、本命は入力を構文として評価しない設計です。 まず動的にテンプレートを組み立てている箇所を洗い出し、変数渡しへ置き換えるのが費用対効果の高い順序になります。

Rails での事例

通常の Rails ビューは、テンプレートファイルに変数を渡す形なのでSSTIは起きません。 問題になるのは、ユーザー入力を含む文字列を実行時にテンプレートとしてコンパイルする実装です。 メール文面やお知らせの差し込みを、こうした形で実装してしまう例があります。

# 危険:ユーザー由来の文字列を ERB として評価している
# "<%= system('id') %>" のような入力でサーバ上のコードが動く
template = "#{@notice.body_from_user}"
ERB.new(template).result(binding)

ERB は Ruby コードをそのまま評価するため、これはテンプレートインジェクションであると同時に、実質的な任意コード実行です。 直し方は、テンプレートを固定し、ユーザー入力は「値」として差し込むことです。

<%# 固定テンプレート。ユーザー入力は locals で渡す %>
<%= render "notices/body", body: @notice.body_from_user %>

利用者に文面のプレースホルダ({{name}} のような差し込み)を編集させたい要件があるなら、ERB のようなコード評価エンジンではなく、式を評価しない単純な置換に限定します。

# コード評価のない安全な置換。gsub で既知のキーだけを埋める
def render_notice(template, name:)
  template.gsub("{{name}}", name)
end

Liquid のようなロジックレス寄りのテンプレートエンジンを使う手もあります。 いずれにせよ、「ユーザーが編集した文字列を Ruby として評価する経路を作らない」ことが要点です。

まとめ

サーバサイドテンプレートインジェクション(SSTI)対策の要点を整理します。

  • 根本原因は「入力が値ではなく、テンプレートの構文として評価される経路があること」。文字列連結でテンプレートを組み立てる形が危険の中心になる
  • 本命の対策はテンプレートを固定し、ユーザー入力は変数(コンテキスト)として渡すこと
  • 文面をユーザーに編集させる要件には、式を評価できないロジックレステンプレート(Liquidなど)か、既知のキーだけを置換する単純な実装で応える
  • ERB は Ruby をそのまま評価するため、ユーザー由来の文字列を ERB.new に渡す実装は実質的な任意コード実行になる
  • メタ文字のフィルタリングはエンジンごとに抜け道があり、本命にはならない。エンジンの権限最小化は被害軽減策として重ねる

点検は ERB.newrender_template_string のような「実行時にテンプレートをコンパイルする呼び出し」の検索から始められます。メール文面・通知・帳票など、文面の差し込みを実装している箇所が重点確認の対象です。

関連して読める記事

SSTIとよく対比されるのがXSS(クロスサイトスクリプティング)です。どちらも「入力が構文として解釈される」点は同じですが、XSSは利用者のブラウザ上で、SSTIはサーバ上で評価されるため、被害の質が変わります。サーバ上での任意コマンド実行に至るという結果の面ではOSコマンドインジェクションと並ぶ脆弱性で、「入力を構文に混ぜない」という対策の原則はSQLインジェクションのプレースホルダとも共通しています。

XSS(クロスサイトスクリプティング)とは?起きるパターンと対策法

XSS(クロスサイトスクリプティング)の仕組みと3つの型、混入しやすいパターン、そして出力時のエスケープを軸にした対策を整理します。React(TypeScript)の dangerouslySetInnerHTML と Rails(ERB)の raw / html_safe を題材に、危険なコードと安全な書き方を具体的なコード例で示します。

2026年7月22日

OSコマンドインジェクションとは?起きるパターンと対策法

OSコマンドインジェクションの仕組みと起きるパターン、シェルを介さず多引数形式でコマンドと引数を分離して渡す対策を整理します。Railsで system にユーザー入力を連結した文字列を渡してしまう危険例と、多引数形式での安全な実装、オプション解釈の残余リスクや Shellwords.escape の位置づけまで具体的なコードで示します。

2026年7月24日

SQLインジェクションとは?起きるパターンと対策法

SQLインジェクションの仕組みと起きるパターン、そしてプレースホルダ(パラメータ化クエリ)を軸にした対策を整理します。Rails(Active Record)で穴が開く where の文字列展開と order のカラム名、その安全な書き方を具体的なコード例で示します。

2026年7月22日
この記事をシェア