ほとんどの場合、Rails 3ではデフォルトでXSS攻撃に対する保護が追加されていることを既にご存じでしょう。 これは、これからは、レールが常にこれを行うため、
hヘルパーを使用してユーザー入力を手動でフィルタリングする必要がないことを意味します。
それにもかかわらず、すべてが最初の外観のように単純ではありません。 次のコードを検討してください。
<strong></strong>!
<%= tag(:p, some_text) %>
<%= some_text %>
上記の例では、HTMLタグの使用を含むいくつかの異なるケースがあります。 最初のケースでは、Railsは
という単語を囲む
<strong>タグをフィルタリングしないでください。 結果は明らかにユーザーが入力したものではありません。 2番目のケースでは、Railsは
<p>内の
some_text必要があります(ただし
<p>全体ではありません)。 最後に、3番目のケースでは、親タグの
some_textをフィルターする必要があります。
some_textの結果が次のようになる場合:
<strong></strong>!
<p><script>evil_js</script></p>
<script>evil_js</script>
これがRailsアプリケーションのどこでも機能するように、
html_safeと呼ばれる新しいアプローチを実装しました。 そのため、文字列が
html_safeである場合(文字列で
html_safe html_safe?を呼び出すことで決定されます)、ERBはそのままにします。 行が
html_safeでない
html_safe 、ERBはページに挿入する前にフィルタリングします。
def tag(name, options = nil, open = false, escape = true)
"<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe
end
ここで、Railsはタグを作成し、
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*内部ストレージを作成することによってのみ)。
この実装の結果、私はこの記録方法を見始めました:
buffer << other_string.html_safe
ここでRailsは
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は実行時にテンプレートの
<% %>以外の部分をフィルタリングしません。これはコンパイル時にこれを処理するため、パフォーマンスへの影響がないためです。
これに対して、元の実装では、XSSは各連結または文字列の
+影響しました。 アプリケーションが
rawヘルパー、またはテンプレート内の
<% %>以外の連結を使用した場合でも影響を受けます。
それにもかかわらず、私はマイケル・コジアスキーに個人的な感謝を表明したいと思います。マイケル・コジアスキーは彼のアイデアの大まかなドラフトを提供してくれました。 彼女は働き、コンセプトを実証し、コミュニティはそれを十分にテストしました。 最後に、彼女は良いスタートを切った。