Aqutras Members' Blog

株式会社アキュトラスのメンバーが、技術情報などを楽しく書いています。

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))}"));

ざっくり説明

流れとしては,

  1. 出力したい文字列をビューに渡してでURLエンコード
  2. それをBase64でエンコードしたものを文字列として出力
  3. JSを使ってBase64のデコードとURLデコード
  4. デコードした文字列をsrcdocに入れる

という感じです. 途中にURLエンコードを挟むのは,base64で日本語をエンコードすると失敗することがあるからです.

iframeのseamless属性は,呼び出し元のスタイルを継承するなど,フレームっぽくないように見せるものです. 現在対応しているブラウザは,主要ブラウザの中では存在しないらしいので,現状は特に意味が無いです. 実際に開発したものでは,別途スタイルを指定してフレーム感をなくしました.

以下のサイトに各要素の説明と対応状況がまとめられていて,参考になりました.

iframe 要素 - HTML | MDN

余談

IEはsrcdocに対応していません. そのためIEに対応したページを作ろうとすると,別の方法が必要になってきます.

余談の余談

久しぶりにIEだけに何かをさせる方法について調べたら,昔の方法が使えなくなっていたので書いておきます.

条件付きコメント

お馴染みの<!--[if IE]-->です.IE10から廃止されていました.

Content Moved (Windows)

javascriptを使った方法

userAgent.indexOf('msie') != -1

ですね. これもIE11から使えなくなっています.

ユーザー エージェント文字列の変更 (Windows)

上のサイトによるとIE11のユーザーエージェントは Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko らしいです.