Reactで安全にリンクを出力する

ReactNode.js
2020-08-15

Reactで入力されたテキストにURLが含まれている場合に、出力する側でそのURLを判定し、自動的にaタグを適応したい。 利用するライブラリは以下の2つ

ライブラリ

Anchorme

テキストに含まれているURLライクな文字列を自動的にaタグに変換してくれる。

import anchorme from 'anchorme';

const text = 'hello https://google.com link.';

const htmlText = anchorme({
    input: text,
    options: {
      attributes: () => {
        const attributes = {
          target: '_blank',
          rel: 'noopener noreferrer'
        };
        return attributes;
      }
    }
  });

console.log(htmlText);
// hello <a href="https://google.com" target="_blank" rel="noopener noreferrer">https://google.com</a> link.

上記の通り、URLライクな文字列をaタグに変換してくれます。

デフォルトではgoogle.comなどの https:// がつかない場合も変換されます。その場合はオプション等で変更することになります。

options: {
  exclude: function(string) {
    if (!string.startsWith("https://")) {
      return true;
    } else {
      return false;
    }
  }
},

本当はタグの変換はクライアント側で変換せず、サーバ側で変換される方が望ましいと思います。

js-xss

js-xssはhtmlライクな文字列を評価し、xssが発生しない安全な文字列に変換(サニタイズ)してくれます。

react上でhtmlを表示したい場合、やむを得ず dangerouslySetInnerHTML を利用することになりますが、ユーザ側で入力されたものなど安全ではないテキストを表示したい場合このライブラリを使って危険なhtml構文を取り除くことができるようになります。

js-xssはデフォルトでformタグやscriptタグを除外するようにフィルターを持っています。今回はaタグのみを対象(許可)としたいので以下のようにしました。

<span dangerouslySetInnerHTML={{
  __html: filterXSS(htmlText, {
    whiteList: {
      a: ['href', 'title', 'target', 'rel'],
    }
  })
}}/>

以上によって、リンクのみをaタグで表示し、その他のタグはサニタイズされた状態で表示できるようになりました。

An image from Notion

avatar
Written by Kyohei Tsukuda who lives and works in Tokyo 🇯🇵 , building useful things 🔧.