31
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

React の dangerouslySetInnerHTML を使用する際に最低限気にするべきこと

Posted at

注意: 使わなくていいなら使わないほうが良いです。

ドキュメントにもそう書いている。
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}} />;
  }
}

まとめ

気合でエスケープするとなるとつらいので一部対応といった形に...

気休めばかりなので、もっとこうした方が良いとかあればコメントください!

31
23
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?