注意: 使わなくていいなら使わないほうが良いです。
ドキュメントにもそう書いている。
https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
クロスサイトスクリプティング(XSS) の可能性が出ます。とだけ書かれていて具体的にどうやってエスケープするべきなのか全然出てこないので、僕の思う方法をまとめてみました。
最低限なのでエスケープ漏れは起こると思っている。
また、React でレンダリングする場合、基本的にはエスケープが自動で行われるので普通は気にしなくていいです。[参照]
使いたい動機とか
何処かからhtmlが送られてきてそれを表示したい。。。的な時ぐらいしか使用用途が思いつかないですが、やる必要が出てくることもあるかと思います。
要件を変えてもらえるほうが圧倒的に良いです。
実際プロダクトには使わなかった。
クロスサイトスクリプティングへの対策
ヘッダー
- X-XSS-Protection: 1; mode=block とりあえず有効にしておく[参照]
- 攻撃されてるっぽいときにレンダリングしないでくれる可能性を残しておく(気休め)
エスケープ
ここに上がっているものすべてに対応したほうが良さそうだけれども全部対応するのはつらすぎるので下記ぐらいでどうにか。。。
- escape-html を使ってエスケープしてから HTML String に組み込む
-
<a>
の href や<iframe>
の src に入れるときは追加でjavascript:
のスキームを拒絶する(気休めかもしれない)
import React from 'react';
import * as escape from 'escape-html';
class Sample extends React.Component {
render() {
const escapedData = escape(this.props.data);
const escapedUrl = escape(this.props.url).replace(/javascript:/g, '');
const html = `
<div data-attr="${escapedData}">
<a href="${escapedUrl}">Link</a>
</div>
`;
return <div dangerouslySetInnerHTML={{__html : html}} />;
}
}
まとめ
気合でエスケープするとなるとつらいので一部対応といった形に...
気休めばかりなので、もっとこうした方が良いとかあればコメントください!