Vue.js上で文字列を展開したい時があります。例えばそれは誰かが投稿したコメントをコンポーネント上に表示する時です。こういった時コメントの改行が反映されていない場合、見栄えが悪くなります。改行を行う必要があります。
HTML上の改行と言えばbrタグです。PHPにはnl2brという改行コードを改行タグに変換する組み込み関数があるぐらいです。
PHP: nl2br – Manual
改行の実現でありがちで危険なアンチパターンはこのnl2br関数を用いたコメントをそのまま表示しようと考えるものです。Vue.jsにはv-htmlというディレクティブがあり、これを用いると普段かかっている安全装置のHTMLエスケープを外し、HTMLとしてパース、実行します。brタグとv-htmlを用いることで改行コードを改行タグに変換して表示できます。
v-htmlはXSSをまあまあ容易に招く危険性を持ちます。まあまあ危険というのは単純な
<script>alert('XSS')</script>
ぐらいならVueの仕組み上実行されず済むからです。とはいえ
<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>
の様な多少の変化球(scriptタグをbase64形式でエンコード、埋め込んだコード中でデコードして実行)であっさり破られるのでやはり危険です。
XSS 脆弱性を容易に引き起こすので、ウェブサイトで動的に任意のHTMLを描画することは、非常に危険です。信頼できるコンテンツにだけ HTML 展開を利用してください。ユーザーから提供されたコンテンツに対しては決して使用してはいけません。
これの対策は実現したい機能に関しての実装を生のHTMLに頼るのでなく個々の別手法を用いるのが一番でしょう。
例えば改行に関してはCSSのwhite-space実現できます。white-spaceは要素内のホワイトスペースをどう扱うか決定するスタイルであり、ホワイトスペースの一種(少なくとも正規表現の\sグループでまとめられる)である改行文字の制御もこれでできます
white-space – CSS: カスケーディングスタイルシート | MDN
上記リンクから引用した次の表の’改行を残す’スタイルを用いれば
と生のHTML実行を用いるまでもありません。
改行 | 空白とタブ文字 | テキストの折り返し | 行末の空白 | |
---|---|---|---|---|
normal |
まとめる | まとめる | 折り返す | 除去 |
nowrap |
まとめる | まとめる | 折り返さない | 除去 |
pre |
残す | 残す | 折り返さない | 残す |
pre-wrap |
残す | 残す | 折り返す | ぶら下げ |
pre-line |
残す | まとめる | 折り返す | 除去 |
break-spaces |
残す | まとめる | 折り返す | 折り返す |