ERBで改行コードをbrタグへ置換する(XSS防止)


更新履歴


2019/03/16

記事を投稿しました。


2019/03/17

頂いたコメントをもとに正規表現の書き方を修正しました。


目標

改行コードを含んだ文字列をブラウザ上で改行された状態で表示させる。


hoge.rb

#改行表示させたいターゲットの文字列

@hoge = 'hoge'+"\n" +'hoge'


結論


hoge.rb

hoge = 'hoge'+"\n" +'hoge'

@escaped_hoge = h(hoge).gsub(/\R/, "<br>")


hoge.html.erb

<%= raw(@hoge) %>



結論についての説明


普通に出力した場合(問題あり)


hoge.html.erb

<%= @hoge %>

<!--
hoge hoge
※改行コードがbrタグとして認識されないので改行表示されない
-->



改行コードをbrタグに置換した場合(問題あり)


hoge.rb

@hoge = 'hoge'+"\n" +'hoge'

#正規表現で置換
@hoge.gsub(/\R/, "<br>")
#\Rは複数存在する改行コードを表すメタ文字


hoge.html.erb

<%= @hoge %>

<!--
hoge<br>hoge
※ERBの機能でhtmlエスケープされているので、brタグがタグとして認識されない
-->



エスケープせずに出力した場合(問題あり)


hoge.html.erb

<%= raw(@hoge) %>

<!--
hoge
hoge
※上手くいったように見えるがhtmlエスケープをしていないためセキュアではない
-->



foo.rb

@foo = 'foo'+"\n" +'foo<script>悪意のあるスクリプト</script>'

@foo.gsub(/\R/, "<br>")


foo.html.erb

<%= raw(@foo) %>

<!--
foo
foo
※悪意のあるスクリプトが実行される(XSS脆弱性)
-->



予めエスケープして出力した場合


foo.rb

foo = 'foo'+"\n" +'foo<script>悪意のあるスクリプト</script>'

#hでhtmlエスケープする
@escaped_foo = h(foo)
#htmlエスケープしたあとにbrタグへ置換するので、brタグはエスケープされずに機能する
@escaped_foo.gsub(/\R/, "<br>")


foo.html.erb

<%= raw(@escaped_foo) %>

<!--
foo
foo<script>悪意のあるスクリプト</script>
※scriptタグはhtmlエスケープされているので単なる文字列として解釈される(目標達成)
-->



Railsの場合、置換処理をhelperとして登録しておくと便利


application_helper.erb

module ApplicationHelper

def nl2br(str)
h(str).gsub(/\R/, "<br>")
end
end


hoge.html.erb

<%= raw(nl2br(@hoge)) %>



番外編


simple_formatを使う


hoge.html.erb

<%= simple_format(h(@hoge)) %>

<!--
上記と出力内容は同じだが、出力がpタグで括られる
-->


無駄にpタグを増やすのが嫌なので個人的には使わないです。