💡

Railsのhtml_safeメソッドとはなにか

2024/09/20に公開

html_safeの挙動

html_safeは、HTMLをエスケープせずにレンダリングするメソッド。通常だと、Railsは出力される文字列を自動でエスケープして、XSS攻撃を防ぐ。しかし、html_safeメソッドを使うと、その文字列が安全であると解釈され、エスケープされずそのままHTMLとして表示される。

わざわざRailsが安全のために自動でエスケープ処理をしてくれるところを、html_safeでエスケープをキャンセルするため、このメソッドを使う場合は非常に慎重になる必要がある。

具体例1

たとえば、以下のようなコードがある場合。

<%= "<strong>Bold Text</strong>" %>

これは、文字列がHTMLタグとして解釈されず、テキストとしてそのまま表示される。Railsがよしなにエスケープしてくれた結果だ。

ちなみに、html_escapeメソッドを実行しても同じ結果になる。

<%= html_escape("<strong>Bold Text</strong>") %>

<!-- 短縮バージョン -->
<%= h("<strong>Bold Text</strong>") %>

html_safeメソッドを使うと、HTMLタグはエスケープされないので、HTMLタグが反映した形で表示される。

<%= "<strong>Bold Text</strong>".html_safe %>

具体例2

以下のような、ブラウザを操作するためのスクリプトがある場合。

<%= "<script>alert('XSS');</script>" %>

ここでも、Railsは自動でエスケープ処理をするため、スクリプトはスクリプトとして解釈されず、ただのテキストとして表示される。

では、html_safeメソッドを加えてみるとどうなるか。

<%= "<script>alert('XSS');</script>".html_safe %>

スクリプトが実行されてしまう・・・!こりゃイカン。

APIリファレンスを読む

html_safeについて、公式のAPIリファレンスを読む。

Marks a string as trusted safe. It will be inserted into HTML with no additional escaping performed. It is your responsibility to ensure that the string contains no malicious content. This method is equivalent to the raw helper in views. It is recommended that you use sanitize instead of this method. It should never be called on user input.
https://api.rubyonrails.org/classes/String.html#method-i-html_safe

  • 文字列を安全だと解釈する
  • HTMLはエスケープされない
  • 悪意のあるコンテンツが含まれていないことを確かめる責任があなたにはある
  • viewで使うrawヘルパーと同じ機能を持つ
  • このメソッドよりもsanitizeメソッドがオススメやで
  • ユーザーが入力したコンテンツに対して呼ばれるべきではない

ソースコード

https://github.com/rails/rails/blob/a11f0a63673d274c59c69c2688c63ba303b86193/activesupport/lib/active_support/core_ext/string/output_safety.rb#L225-L227

ではどうすればいいのか

公式リファレンスがオススメしているとおり、ユーザーがHTMLを入力することが許可されている場合や、特定のHTMLタグや属性を許可したい場合はsanitizeメソッドを使う。

具体例1

<%= sanitize("<strong>Bold Text</strong>") %>

👇 strongタグが反映されている

具体例2

<%= sanitize("<script>alert('XSS');</script>") %>

👇 scriptタグが除去されている

ちなみにsanitizeとは「消毒する」「清潔にする」という意味を持つ。
リファレンスはこちら。
https://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html#method-i-sanitize

Discussion