Edited at

[Rails]ERBのエスケープを自在に扱おうぜ

More than 3 years have passed since last update.


コメントにてご指摘をいただきました


HTMLタグを動的に生成する必要がある場合も、content_tagや(aタグでは)link_toなど、Railsの用意しているヘルパーを使えば、HTMLとして出力するかエスケープするかを適宜判断してくれます(自分でhやhtml_safeしなくて問題ありません)。



using_helper.rb

def return_url2(text)

link_to text, 'http://google.com/'
end


純粋な文字列リテラルを.html_safeするのはありかもしれませんが、どこから来るかわからない入力で、テキストからHTMLを生成するのは、(ユーザーからHTMLを受け付けることが本当に必要な場合など)よほどの場合をのぞいて避けるべきでしょう。



Rails3からはHTMLタグが自動エスケープする

Rails3からの機能らしいんですが、

ERBで

<%= @text %>

とかやって@text内の文字列をHTMLに変換するときにHTMLタグ等を自動でエスケープするようになってます。

これはユーザーに任意で文字列を入力してもらうときのセキュリティ対策として必須です。

けどHTMLタグをHelperとかで作成したい場合とか困ります。


application_helper.rb

def return_url

return "<a href="http://google.com">http://google.com</a>"
end


test.html.erb

<%= return_url %>


↓こうHTML出力される

<a href="http://google.com">http://google.com</a>


html_safeメソッドを使おう

そんなときは html_safeメソッドを使う

<%= return_url.html_safe %>

とすると、http://google.com がこちらで意図したとおりaタグで出力されます。


けどセキュリティ的に心配

さっきのHelperメソッドレベルであればhtml_safeメソッドを使うだけで問題ないんですが、ユーザーが任意で入力できるテキストにこちらが意図してHTMLタグを埋め込みたい場合に困ります。

例えばメッセージ等の中にURLが組み込まれている場合、それをaタグで囲ってブラウザ上でクリックできる状態(=有効化)にしたい。。

けどメッセージはユーザーが任意で入力できるため、ユーザーが入力したHTMLタグ等はエスケープ(=無効化)したい。。

という割とよくある?ケースにはこうしたほうが良いです。


test.html.erb

<%= return_url2(h(@test_text)).html_safe %>


ちょっとわかりづらいので順を追って。。

1.controllerから取得したテキストをhメソッドでエスケープ(無効化)します。


test.html.erb

h(@test_text)


2.エスケープした後の@test_textをHelperメソッドのreturn_url2に渡します。

return_url2メソッドは任意)


test.html.erb

return_url2(h(@test_text))


3.return_url2メソッドの結果をhtml_safeにする

(こちらが意図して付けたHTMLタグは有効化する)


test.html.erb

return_url2(h(@test_text)).html_safe


4.完成。


test.html.erb

<%= return_url2(h(@test_text)).html_safe %>



まとめ

html_safeメソッド(HTMLタグの有効化)とhメソッド(HTMLタグのエスケープ=無効化)をきちんと使い分ければHTMLタグエスケープもあなたのもの!

※もうちょっといい書き方あるよってひとは是非教えて下さい!!