テンプレートインジェクションって?
テンプレートエンジンやjsのフレームワークを使用しているアプリケーションに対して、文字列展開される記法を利用して、santizeの漏れをつき任意のプログラムを実行させる攻撃方法の一つです。
広義のxssに近いような攻撃ですね。
例えばサーバーサイドをrails、フロントエンドをvue.jsという構成でアプリケーションが作成され、
一般ユーザーから入力を受け付けて表示する機能があるとします。
ここで悪意のあるユーザーが、攻撃対象のwebサイトが使用しているフロントエンドフレームワークをvue.jsだと仮定して攻撃します。
文字列の展開に使われる{{を使用して以下の文字列を入力してきました。
{{constructor.constructor('alert(1111111111)')()}}
現状のrailsの仕様だと、
部分的に文字列表示をrailsで行っている箇所で {{ マスタッシュがエスケープの対象になっていません。
なので、vue.jsのテンプレートと解釈されて中の文字列がjsとして実行されてしまいます。
なぜ、これが怖いのか?
という説明を今さらしてもあれなのですが、この中で任意のjsを実行できると訪問したユーザーの情報を他サーバーに送信するなどなんでもできちゃいますよね。
対応
でどうやって対応したの?
まあセキュリティ対策の基本で入力で弾く&出力で置き換えるをやっていきます。
入力部分での対応
入力時にマスタッシュ文字がある場合弾いてあげます。
controllerがパラメーターを受け取る前後で対応するか、modelの保存直前で対応するか迷ったのですが、
railsのstrong parameterをいじるのが難しかったので、modelで対応しています。
class BaseModel < ApplicationRecord
self.abstract_class = true
def delete_vue_template
string_value_keys = self.attributes.map do |key, value|
key if value.class == String
end
string_value_keys.compact!.each do key
self[key].replace('{{', '{ {').replace('}}', '} }')
end
end
end
該当のmodelに
before_validation :delete_vue_template
を記載してあげています。
出力部分での対応
大体のrailsアプリケーションでsanitizeが使われていたり、simple_formatで内部的に呼ばれているかなと思いますので、そこに手を入れて行こうとと思います。
ApplicationHelperにsanitizeメソッドを作成して、オーバーライドしてあげます。
simple_formatを使っている方も多いと思いますのでそちらでも自動で適用されるよう工夫しています
def simple_format(string, options = {})
super(sanitize(string, tags: %w[p br strong]), options)
end
def sanitize(html, options = {})
html.replace('{{', '{ {') if html.class == String
super(html, options)
end
感想&追記
セキュリティ検査を会社で行い、対応しようと思った際にあまり資料がなかったのでrails&vue.jsのアプリケーション向けに資料に致しました。
もっとこうやった方いいとか、記載に誤りや視点に抜け漏れがあった際にはコメント等頂けると嬉しいです。
編集リクエストでも助かります。
他の対応方法
angular.jsのドキュメントには一部記載があります。
https://angular.jp/guide/security#offline-template-compiler
オフライン・テンプレート・コンパイラはテンプレートインジェクションと呼ばれる脆弱性を確実に防止し アプリケーションのパフォーマンスを大幅に向上させます。プロダクション環境ではオフラインテンプレートコンパイラを使い、 動的にテンプレートを生成しないようにしましょう。Angularはテンプレートコードを信頼するので、 テンプレート、特にユーザーデータを含むテンプレートを生成すると、Angularの組み込みの保護が回避されます。 Angularはテンプレート文字列を全面的に信頼するため、動的なテンプレート生成は常にXSSの危険性を有します。フォームを安全に動的に構築する方法については Dynamic Forms のガイドを参照してください。
既にリリースしていてこの機能を使っているなら変更する手間がかなり大きいですが、動的テンプレートを生成しないようにしておくのもいいかなと思います。