h
ヘルパーを使用してユーザー入力を手動でフィルタリングする必要がないことを意味します。
それにもかかわらず、すべてが最初の外観のように単純ではありません。 次のコードを検討してください。
上記の例では、HTMLタグの使用を含むいくつかの異なるケースがあります。 最初のケースでは、Railsは<strong></strong>!
<%= tag(:p, some_text) %>
<%= some_text %>
という単語を囲む
<strong>
タグをフィルタリングしないでください。 結果は明らかにユーザーが入力したものではありません。 2番目のケースでは、Railsは
<p>
内の
some_text
必要があります(ただし
<p>
全体ではありません)。 最後に、3番目のケースでは、親タグの
some_text
をフィルターする必要があります。
some_text
の結果が次のようになる場合:
これがRailsアプリケーションのどこでも機能するように、<strong></strong>!
<p><script>evil_js</script></p>
<script>evil_js</script>
html_safe
と呼ばれる新しいアプローチを実装しました。 そのため、文字列が
html_safe
である場合(文字列で
html_safe
html_safe?
を呼び出すことで決定されます)、ERBはそのままにします。 行が
html_safe
でない
html_safe
、ERBはページに挿入する前にフィルタリングします。
ここで、Railsはタグを作成し、def tag(name, options = nil, open = false, escape = true)
"<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe
end
teg_options
コンテンツ
teg_options
フィルタリングする
teg_options
、タグの本文全体を安全としてマークします。 その結果、ユーザーが挿入したコンテンツはフィルターされますが、
<p>
と
</p>
は変更されません。
Koz プラグイン rails-xssの最初の実装では、すべての行に特別なフラグを追加することにより、指定された条件が満たされました。 Railsアプリケーションは必要な行を安全であるとマークしましたが、Rails自体は
+
および
<<
メソッドを再定義したため、行が変更された場合、結果の行はそれに応じてマークされます。
ただし、レールのパフォーマンスを最後にテストしたときに、各文字列の連結をオーバーライドすると、パフォーマンスがかなり低下することに気付きました。 さらに、このドロップは、テンプレート内の挿入数
<%= %>
に直線的に依存していました。 大きなテンプレートはコストを吸収しませんでした(テンプレートごとに1つの呼び出し
<%= %>
かのように)が、増加するだけでした。
この問題についてさらに考えた後、Ruby APIへの影響をさらに少なくして、まったく同じ機能をより生産的な方法で実装できることが明らかになりました(後にRubuniusのKoz、Jeremy、Evan Phoenixによって確認されました)。 問題自体は非常に複雑なので、古い実装の詳細については説明しませんが、新しいXSS保護の使用方法について説明します。 以前にKozプラグインを使用したことがあるか、Railsの予備リリースを既に使用している場合、今日のコミットはそれほど変わりません。
安全なバッファー
Rails 3では、ERBバッファーは
ActiveSupport::SafeBuffer
インスタンスです。 SafeBufferは
String
継承し、
+
、
concat
<<
オーバーライドします。
- 他の行が安全な場合(つまりSafeBuffer)、バッファは単純に連結します
- 他の文字列が安全でない(つまり、単純な文字列である)場合、バッファはフィルタリングを実行してから連結します
html_safe
を呼び出すと、
SafeBuffer
ラッパーが返されます。
SafeBuffer
タイムラインから継承されるため、Rubyはラッパーを非常に効率的に作成します(共有
char*
内部ストレージを作成することによってのみ)。
この実装の結果、私はこの記録方法を見始めました:
ここでRailsはbuffer << other_string.html_safe
SafeBuffer
の新しい
SafeBuffer
を
other_string
、それを元の
SafeBuffer
<<
メソッドに
SafeBuffer
。このメソッドは(メソッド)新しい
SafeBuffer
安全かどうかを確認します。 そのような場合、
safe_concat
が作成されました。元のconcatメソッドを使用するバッファーの新しいメソッドで、新しい
SafeBuffer
を作成してセキュリティをチェックする必要がなくなりました。
同様に、
ActionView
concatおよび
safe_buffer
は、バッファーに対するconcatおよび
safe_buffer
プロキシメソッドです。そのため、チェックおよびフィルタリングを行わずにバッファーと組み合わせる必要があるHTMLテキストがある場合、ヘルパーでsafe_concatを使用できます。
ERBは、テンプレートの
<% %>
safe_concat
<% %>
タグ以外の
safe_concat
場所で
safe_concat
内部的に使用します。 これは、今日の私のコミットでは、XSS保護コードがそのような場合のパフォーマンスに影響しないことを意味します(つまり、実際にはすべてのプレーンテキストをスキャンします)。
最後に、ERBは
raw
ヘルパーを認識できるようになったため、
<%= raw some_stuff %>
ように記述すると、ERBは
safe_concat
に使用し、
safe_concat
の作成と
html_safety
チェックを
html_safety
ます。
結論
つまり、「XSS保護」とは次のことを意味します。
- 通常の文字列が
<%= %>
で指定されている場合、Railsは常にそれをフィルタリングします -
SafeBuffer
が<%= %>
で提供される場合、Railsはそれをフィルタリングしません。 文字列からSafeBuffer
を取得するには、その上でhtml_safe
メソッドを呼び出す必要があります。 XSS保護は、html_safe?
制限されているパフォーマンスにほとんど影響しhtml_safe?
-
raw
ヘルパーを<%= %>
に渡すと、Railsはテンプレートのコンパイルの段階でこれを検出し、パフォーマンスに影響を与えません(つまり、この場合、html_safe
のチェックはhtml_safe
ません) - Railsは実行時にテンプレートの
<% %>
以外の部分をフィルタリングしません。これはコンパイル時にこれを処理するため、パフォーマンスへの影響がないためです。
+
影響しました。 アプリケーションが
raw
ヘルパー、またはテンプレート内の
<% %>
以外の連結を使用した場合でも影響を受けます。
それにもかかわらず、私はマイケル・コジアスキーに個人的な感謝を表明したいと思います。マイケル・コジアスキーは彼のアイデアの大まかなドラフトを提供してくれました。 彼女は働き、コンセプトを実証し、コミュニティはそれを十分にテストしました。 最後に、彼女は良いスタートを切った。