RailsでHTMLタグを含む文字列をプレビューしつつXSSを防ぐ方法
こんにちは miです.
掲示板のようなものを作ろうとした時など,投稿された内容のうちHTMLのスタイル部分はプレビューしたいけど,スクリプトは動いてほしくないというような場面があります.
先日Railsでシステムを作っていてそのような場面に遭遇したため,方法を検討しました.
方法
iframe sandbox
を使うことにしました.
HTML5から追加されたもので,フレーム内のコンテンツに対して制限をかけることが出来ます.
文字列はsrcdoc
にセットすることで,新しくページを生成することなく表示します.
実際に書いたコード
ビュー部分のコードです.slim
で書かれています.
変数str
に出力したい文字列をURLエンコードした後Base64でエンコードしたものが入っています
iframe id="raw-iframe" seamless=true sandbox=true srcdoc="" javascript: $('#raw-iframe')[0].srcdoc = decodeURI(window.atob("#{Base64.strict_encode64(URI.encode(str))}"));
ざっくり説明
流れとしては,
- 出力したい文字列をビューに渡してでURLエンコード
- それをBase64でエンコードしたものを文字列として出力
- JSを使ってBase64のデコードとURLデコード
- デコードした文字列をsrcdocに入れる
という感じです. 途中にURLエンコードを挟むのは,base64で日本語をエンコードすると失敗することがあるからです.
iframeのseamless
属性は,呼び出し元のスタイルを継承するなど,フレームっぽくないように見せるものです.
現在対応しているブラウザは,主要ブラウザの中では存在しないらしいので,現状は特に意味が無いです.
実際に開発したものでは,別途スタイルを指定してフレーム感をなくしました.
以下のサイトに各要素の説明と対応状況がまとめられていて,参考になりました.
余談
IEはsrcdoc
に対応していません.
そのためIEに対応したページを作ろうとすると,別の方法が必要になってきます.
余談の余談
久しぶりにIEだけに何かをさせる方法について調べたら,昔の方法が使えなくなっていたので書いておきます.
条件付きコメント
お馴染みの<!--[if IE]-->
です.IE10から廃止されていました.
javascriptを使った方法
userAgent.indexOf('msie') != -1
ですね. これもIE11から使えなくなっています.
上のサイトによるとIE11のユーザーエージェントは
Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
らしいです.