5.1 安全な出力
5.1.1 開発の動機
HTMLテンプレートにデータを挿入する方法は、きわめて慎重に設計する必要
があります。たとえば、@review.titleを何の工夫もなくそのままHTMLに式展開するようなことは絶対にすべきではありません
。もしこのレビューのタイトルが仮に「Flanagan & Matz rules!」だとしたら、出力はwell-formedになりません。well-formedにするには、&->&のようにエスケープしなければなりません。さらに、ユーザーがレビューのタイトルに細工をして、悪意のあるHTMLをタイトルに含めれば、巨大なセキュリティホールになる可能性すらあります。このリスクの詳細については、セキュリティガイドのクロスサイトスクリプティングの節を参照してください。
-
@review.title
をHTMLに展開してはならない。
5.1.2 安全な文字列
Active Supportには「(html的に) 安全な文字列」という概念
があります。安全な文字列とは、HTMLにそのまま挿入しても問題がないというマークが付けられている文字列
です。マーキングさえされていれば、「実際にエスケープされているかどうかにかかわらず」その文字列は信頼されます。文字列はデフォルトでは「unsafe」とマークされます。
"".html_safe? # => false
与えられた文字列にhtml_safeメソッドを適用することで、安全な文字列を得られます。
s = "".html_safe s.html_safe? # => true
ここで注意しなければならないのは、
html_safeメソッドそれ自体は何らエスケープを行なっていない
ということです。安全であるとマーキングしているに過ぎません。s = "<script>...</script>".html_safe s.html_safe? # => true s # => "<script>...</script>"
すなわち、特定の文字列に対して
html_safeメソッドを呼び出す際には、その文字列が本当に安全であることを確認する義務
があります。
- html_safeメソッドそれ自体は何らエスケープを行なっていない
安全であると宣言された文字列に対し、安全でない文字列をconcat/<<や+で破壊的に追加すると、結果は安全な文字列
になります。安全でない引数は追加時にエスケープされます。"".html_safe + "<" # => "<"
安全な引数であれば、(エスケープなしで)直接追加されます。
"".html_safe + "<".html_safe # => "<"
基本的にこれらのメソッドは、通常のビューでは使わないでください
。現在のRailsのビューでは、安全でない値は自動的にエスケープされる
ためです。<%= @review.title %> <%# 必要に応じてエスケープされるので問題なし %>
- 上記のメソッドは使わない!
- 現在のRailsのビューでは、
安全でない値は自動的にエスケープされる
何らかの理由で、
エスケープされていない文字列をそのままの形で挿入したい場合は、html_safeを呼ぶのではなく、rawヘルパーをお使いください
。<%= raw @cms.current_template %> <%# @cms.current_templateをそのまま挿入 %>
あるいは、rawと同等の<%==を使います。
<%== @cms.current_template %> <%# @cms.current_templateをそのまま挿入 %>
rawヘルパーは、内部でhtml_safeを呼び出します。
def raw(stringish) stringish.to_s.html_safe end
定義はactive_support/core_ext/string/output_safety.rbにあります。
- エスケープされていない文字列をそのままの形で挿入したい場合は、html_safeを呼ぶのではなく、rawヘルパーをお使いください
- rawヘルパーとは?
raw
This method outputs without escaping a string. Since escaping tags is now default, this can be used when you don’t want Rails to automatically escape tags. This is not recommended if the data is coming from the user’s input.
- もっとrubyを読めるようになりたい。
感想
inputタグから入力しても自動的にエスケープされるからscriptが発動しないことを知った。
しかし他の方法があるなら知りたい。(調べても探すことができなかった。)
できればコメントで教えてください。(理解できるかどうかわかりません)