simple_formatについて:改行の反映とXSSまとめ

railsの勉強でエラーにぶつかりまくって、パンクしそうなのでメモに残そうと思い、この記事を書きました。

初学者なので間違っていればご指摘お願いします。

##前提
参考書として使っている現場railsの学習で、タスク管理アプリを作っていた時に気になったことです。

タスク詳細画面のviewを作っていた時に、最初はこのように記述していました。
(ファイルの形式はslimです)
```
td = @task.description
```
![スクリーンショット 2023-05-18 21.06.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676271/97b7b0ff-6d16-e36c-184e-705201a09423.png)

ブラウザ表示して、詳しい説明フォームには以下のように改行して入力しました。

hello
good morning

ですが、なぜか改行が反映されず…。HTML変換後はこのようなコードになっていました。
![スクリーンショット 2023-05-18 21.07.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676271/89ecc8ff-5047-1c4a-c877-0afd606da46e.png)

```
<td>hello good morning</td>
```
その後書籍を見て、simple_formatメソッドというものを使わないと改行ができないと知りました。ただ、書籍を見ても何のことだか分からなかったので色々調べてみました。
## 原因
複数行のテキストを入力できるということは、文章を改行することもありえますよね。
ただ、simple_formatを使わない場合、文章を改行したコードはHTML変換したときに`<br>タグ`を含んで改行を反映してはくれないのです。

なぜなら、HTMLコード自体の改行として扱われてしまうからです。
つまり、例えると「エディタ上でコードを見やすくするために改行している状態」とみなされてしまうのです。（`<br>`タグを含まない状態ということ）
## simple_formatメソッドとは？
そこで、simple_formatメソッドです。

これは、複数行のテキストを入力するときブラウザ上で改行されて表示できるようにするためのメソッドです。
```
simple_format(文字列,オプション={},HTML属性={}, or イベント属性={})
```
simple_formatはデフォルトで文字列を`<p>タグ`で囲みます。また、連続した改行は`</p><p>`が付与されます。
```
<% text = "テキスト
テキスト

テキストテキスト" %>
<%= simple_format(text) %>
```
```
<p>テキスト<br>テキスト</p><p>テキストテキスト</p>
```
今回、参考書には文字列以外にもいろいろなオプションが付けられていました。次からはオプションについて説明していきます。
## XSS(クロスサイトスクリプティング)
まず、オプションの説明の前にXSSについて知っておきましょう。

XSSとは、ユーザーに表示するコンテンツへ、悪意のある第三者が任意の操作を行う攻撃のことです。

例えば、Webアプリケーションのコメント欄に、悪意のあるユーザーが`<script>悪意のあるコード</script>`のような文字列を入力したとします。

もし、何もセキュリティ対策をしていない場合、悪意のある文字列がブラウザに表示された際にスクリプトとして解釈され実行されてしまいます。

このような悪意のある攻撃から、Webアプリケーションのセキュリティが犯されないようにしないといけません。

XSS対策には、ユーザーの入力した文字列をそのままHTML内に埋め込んで表示せずに、エスケープする必要があります。
### エスケープとは？
| 文字列 | HTML表現形式 |
|:-:|:-:|
| < | `&lt;` |
| > | `&gt;` |
| & | `&amp;` |
| “ | `&quot;` |

上の表のように文字列に対して「<」を無害なHTML表現形式「&lt;」に置き換えてくれることをエスケープと言います。

これによって、危険なHTMLタグとして解釈されないように加工してからブラウザに文字列を表示できます。
### 特殊文字
さらに詳しくいうと、HTML文では、「<」「>」「&」「”」などの文字は特別な意味を持ちます。そのため、<>を使うHTMLタグを含む文字列をそのまま出力すると違う意味になってしまいます。
```
例) <>で囲まれた文字列を出力したい

<% text = "<重大発表>お見逃しなく" %>
<%= text %>
```
```
出力結果)<重大発表>は文字列ではなくタグとして認識されてしまい出力されない

お見逃しなく
```
つまり、違う意味になってしまうのをエスケープ(回避)する必要があります。

また、simple_formatではタグが文字列に埋め込まれている場合はエスケープされなくなってしまう注意点もあります。
### simple_formatを使用しない場合
例えば、simple_formatを使用しない通常の文字列にタグを埋め込んだ場合
```
<% text = "<h1>テキスト
テキスト

テキスト<h1>" %>
<%= text %>
```
```
&lt;h1&gt;テキスト
テキスト

テキスト&lt;h1&gt;
```
このように`<h1>`タグが自動でエスケープされています。
### simple_formatを使用した場合
しかし、simple_formatを使用した文字列の中にタグを埋め込んだ場合
```
<% text = "<h1>テキスト
テキスト

テキスト<h1>" %>
<%=  simple_format(text) %>
```
```
<p><h1>テキスト
<br>テキスト</p>

<p>テキスト</h1></p>
```
このように、`<h1>`タグはエスケープされずにそのまま出力されています。

railsのビューでは、ユーザーが入力した文字列を出力する際に自動的にHTMLをエスケープしてくれる機能が備わっています。

ですが、中にはプログラマーが意図的に用意した文字列を使いたい場合もあります。その際は、自動エスケープされると困ってしまいますね。

このような場合に、使える便利なオプションが用意されています。
### sanitize
sanitizeオプションをつけることによって、テキストに含まれる一部の危険なHTMLタグを取り除いてくれます。

ある程度タグをそのまま出したいものの、危険なタグは出力しないようにしたい場合に使います。

さらに、一部のタグではなく、すべてのタグを安全に表示したい場合はfalseにしてhメソッドを使います。

### hメソッド
HTMLタグをエスケープしてくれるメソッドで`html_escape`と同じ機能です。

一部ではなく、すべてのHTMLタグを安全に表示したい時に`sanitizeオプション`を`false`にした状態で`hメソッド`を一緒に使います。
### wrapper_tag
simple_formatの文字列はデフォルトで`<p>`タグで囲まれます。ですので、`<div>`タグなど他のタグで囲みたい場合は、`wrapper_tagオプション`を使えば、置換することができます。
## 改行を反映する
それでは、書籍通りコードを上から下に変えてみました。
```
#変更前
td = @task.description

#変更後
td = simple_format(h(@task.description), {}, sanitize: false, wrapper_tag: "div")
```
全てのタグを安全に表示したいので、`sanitize`を`false`にして`hメソッド`をつけています。
また、`pタグ`ではなく`divタグ`で囲みたいので`wrapper_tag`に`div`を指定してます。

すると、改行が反映されるようになりました！
HTML変換後のコードにも`<br>タグ`が含まれています。

![スクリーンショット 2023-05-18 21.36.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676271/40ac9295-e20d-0a0c-cedd-5e7523571f82.png)
```
<td><div>"hello"<br>"good morning"</div></td>
```
## まとめ
今回は、文字列の改行をブラウザに反映するためのメソッドについてまとめました。
私も調べていくうちに新しい知識が増えてとても勉強になりました！参考にされば嬉しいです。

最後まで見ていただきありがとうございます。