simple_formatを使ってテキストエリアに入力した文章を改行表示する - サニタイズとエスケープの違いを理解する
ユーザーがテキストエリアに入力した文章。改行したはずなのに、表示してみると改行が消えていた…
HTMLでは、改行コード(\n)は単なるスペースとして扱われるため、意図した通りの表示になりません。
Railsのヘルパーメソッドsimple_format
を使って入力されたテキストをHTML形式に変換することで、HTMLに改行を反映させることができます。
調査
テキストエリアに入力した改行を含むテキストはどう保存されているか確認します。
文章1
文章2
文章3
> Article.last
=>
#<Article:0x0000ffff6432db88
body: "文章1\n\n文章2\n\n\n文章3",
HTMLでは、改行文字(\n)は表示時に空白文字として解釈されます。つまり、与えられたテキストは
文章1 文章2 文章3
と、単一の改行文字(\n)は単なるスペースとして扱われ、複数の改行(\n\n)も単一のスペースとして解釈されます。
HTMLで、改行を反映させるには、<br>
タグを使用する、<p>
タグで段落を分けるの方法があります。
また、CSSで"white-space: pre-wrap"
クラスを利用する方法もあります。 https://developer.mozilla.org/en-US/docs/Web/CSS/white-space
simple_format
を利用することで改行コード(\n)を<br>
タグ、<p>
タグに変換することでHTMLに改行を反映させることができます。
simple_formatを使う
simple_formatの挙動
simple_format
はフォーマットルールに従ってテキストをHTMLに変換します。
- \n\nは段落と見なされ
<p>
タグに変換する - \nは改行と見なされ
<br>
タグに変換する。
# \nは<p>タグ、<br>タグに変換される
simple_format ("あいうえお\n\nかきくけこ\nさしすせそ")
=> "<p>あいうえお</p>\n\n<p>かきくけこ\n<br />さしすせそ</p>"
- デフォルトで入力をサニタイズしますが、エスケープは行いません。つまり、HTMLタグはページに表示されますが、悪意のあるコードはすべて削除されます。
- サニタイズ: HTMLから悪意のある部分(<script>タグなど)を削除する処理です。安全なタグ(<a>, <b>など)は残します。
- エスケープ: HTMLの特殊文字(<, >, &など)を、文字として表示される安全な形式(<, >, &など)に変換する処理です。これにより、ブラウザがそれらをタグとして解釈するのを防ぎます。
# aタグを含むテキストを入力する場合はaタグとして表示される
simple_format('<a href="http://example.com/">Example</a>')
=> "<p><a href=\"http://example.com/\">Example</a></p>"
# 悪意のあるコードはサニタイズされる
> simple_format('<a href="javascript:alert(\'no!\')">Example</a>')
=> "<p><a>Example</a></p>"
- すべてのコンテンツをエスケープする場合(HTMLタグとして扱わずに文字列として扱いたい場合)は、
h
メソッドを使う- simple_formatでは、デフォルトでimgタグの利用は許可されています。ただし、悪意のある属性(onerrorなど)は自動的に削除されます。すべてのタグを無効化したい場合は、hメソッドを利用します。https://api.rubyonrails.org//classes/ActionView/Helpers/SanitizeHelper.html
> simple_format h('<a href="http://example.com/">Example</a>')
=> "<p><a href=\"http://example.com/\">Example</a></p>"```
hの挙動 - XSS対応
hメソッドは、XSS攻撃を防ぐためにユーザーが入力した悪意のあるコード(<script>alert("XSS")</script>)を実行可能なコードではなく、文字として表示される安全な形式に変換します。
例えば、zennのエディタでは、<script>alert("XSS")</script>を入力してもエスケープ処理されて文字列として表示されています。
> h('<script>alert("XSS")</script>')
=> "<script>alert("XSS")</script>"
まとめ
ユーザーが入力したテキストの改行を保持して表示するには、simple_format
を使う。
hメソッドの使い分けはユーザーの入力値に対する扱いから検討する。
-
simple_format @article.body
: ユーザーが入力したHTMLタグの一部(<a>など)を意図的に有効にしたい場合。 -
simple_format h @article.body
: ユーザーの入力内容をすべて安全なテキストとして扱い、タグとして解釈させたくない場合。
コード | サニタイズ | エスケープ | \nの表示 |
---|---|---|---|
@article.body | なし | なし | \nは空白文字として扱う |
simple_format @article.body | <script>タグなどを削除する | なし | \nは<br> タグ、<p> タグに変換 |
simple_format h @article.body | エスケープによりタグ無効化 | あり。<や>などの特殊文字が< や> にエスケープされる |
\nは<br> タグ、<p> タグに変換 |
Discussion