7
3

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 1 year has passed since last update.

Reactでマークダウン記法を実装しよう!

Last updated at Posted at 2022-12-30

はじめに

.
こんにちは!かほです♪
現在、本業ではエンジニア業務と技術広報業務に従事しています。

エンジニア業務ではReact/Next.jsを用いたフロントエンド開発に関わる機会が多いですが、
今回は技術メモの中からマークダウン記法の実装方法、それに伴うXSS対策について試した方法を説明します☺️

この記事の読者対象

・Reactでマークダウン記法を実装したい方
・XSS対策について知りたい方

出来上がったもの

メッセージのフォームにマークダウン記法で入力した値が、プレビューでリアルに反映されてるというものです。

コードの全体像

App.tsx
import './App.css';
import { useState } from 'react';
import { marked } from "marked";
import sanitizeHtml from 'sanitize-html';

function App() {
  const [markdown, setMarkdown] = useState('');
  const markedText = sanitizeHtml(markdown, {
    allowedTags: [],
    disallowedTagsMode: 'recursiveEscape',
  });

  marked.setOptions({
    gfm: true,
    breaks: true,
  });

  const htmlText = marked.parse(markedText);


  return (
    <>
      <div>
        <form>
          <label>
            メッセージ
          </label><br/>
          <textarea name="name" rows={10} cols={40} onChange={(e) => setMarkdown(e.target.value)}/>
        </form>
      </div>
      <div>
        <p>プレビュー</p>
        <div className='bg-gray-200 p-3 text-sm w-full prose prose-sm'>
          <div dangerouslySetInnerHTML={{ __html: htmlText }} className='w-3/4' />
        </div>
      </div>
    </>
  );
}

export default App;

ここから数カ所に分けて実装方法を確認します。

メッセージフォーム内の値を管理しよう!

まずはフォーム内の値を保持、状態管理します。
下記のようにuseStateで入力した値を状態管理し、onChangeイベントでフォームの入力欄に変更があった場合、プレビュー欄に文字を起こせるよう設定します。

const [markdown, setMarkdown] = useState('');
<textarea name="name" rows={10} cols={40} onChange={(e) => setMarkdown(e.target.value)}/>

マークダウンの表記をHTMLに変換しよう!

次はフォーム内でマークダウン表記した値をHTMLに変換するため、markedライブラリを使用します。

$ npm i --save-dev @types/marked

また、markedを使用する際は複数のオプションが存在します。
わたしが今回使用したオプションは、文字を改行表示するものです。
上記の動画にもあるようにフォーム内で改行して文字を打った場合、プレビューでも文字が改行されます。
オプション実装方法は、オプションを参考に下記のように書きました。

marked.setOptions({
    gfm: true,
    breaks: true,
  });

HTMLを表示させよう!

入力した値をパース処理したものをmarkedを用いてHTMLに変換するため、下記のように記述します。

const htmlText = marked.parse(markedText);

次にReactにHTMLを挿入します。その場合はdangerouslyuSetInnerHTML属性に__htmlプロパティを持つObjectを渡してあげる必要があります。

また、メッセージフォームで入力したタグのスタイルがブラウザー上で可視化されるように、
Typographyプラグインを使用します。

$ npm install -D @tailwindcss/typography
 <div dangerouslySetInnerHTML={{ __html: htmlText }} className='w-3/4' />

これでおしまい!と思ったそこのあなた!!!
ちょっと待ってください!
dangerouslyuSetInnerHTMLは名前の通り、とても危険な操作です(泣)

XSS(クロスサイトスクリプティング)対策のために文字をサニタイズしましょう!!!

XSS対策...???

XSSってそもそもなんぞや?

XSS=クロスサイトスクリプティングについて知らない人がいると思うので説明します。

XSSとは、Webアプリケーションへのサイバー攻撃手法の一つです。WEBアプリケーションの脆弱性を利用して悪意のあるコードを実行させるといった内容です。

言葉だけではわからないと思うので、実際の例を説明します。
まずは下記の画像を見ましょう。(画像が静止している場合はクリックして見てね)

画像ではメッセージフォームに「イタズラしちゃうぞ」という言葉をaタグで囲んで入力しました。
XSS対策していない場合、タグはHTMLに変換されないまま、タグとしての機能を保持して出力されてしまいます。そうして上記のようにタグを使用して別サイトへの誘導も可能にするのです。

この特性を利用として、サイトで悪意のあるポップやリンクを踏ませることができてしまいます。

XSS対策を実装しよう!

XSS対策をする必要性が分かったところで文字のサニタイズを実装するために、sanitize-htmlを使用します。

npm i --save-dev @types/sanitize-html

sanitize-htmlをしようとする場合も複数のオプションが存在します。第一引数に入力した値、第二引数にオプションを設定しましょう。

const markedText = sanitizeHtml(markdown, {
    allowedTags: [],
    disallowedTagsMode: 'recursiveEscape',
});

今回使用したオプションはallowedTagsdisallowedTagsModeです。

allowedTagsに設定する値は、xss対策しないタグ名となります。今回はすべてのタグ名に対策を加えたいため、空文字と設定しました。

disallowedTagsModeに設定する値は指定されていないタグ名に対しての動作です。今回はallowedTagsにタグが設定されているいないに関わらず、すべてのタグをエスケープするために、recursiveEscapeと設定しました。

最後に

これで実装はおしまいです!

今回はReactを使用したマークダウン記法の実装方法と、それに伴うXSS対策について説明しました。
今後は主にフロントエンド周辺、コミュニティ運営、Tech PR(技術広報)の記事を中心に書いていく予定ですので、気になる方はぜひフォローをよろしくお願いします♪ではでは〜

Twitterアカウント:https://twitter.com/kaho_eng

参考資料

@types/marked
https://www.npmjs.com/package/@types/marked

Marked Documentation
https://marked.js.org/using_advanced#options

Typographyプラグイン
https://tailwindcss.com/docs/typography-plugin

apostrophecms/sanitize-html
https://github.com/apostrophecms/sanitize-html

クロスサイトスクリプティング(XSS)とは?わかりやすく解説
https://www.shadan-kun.com/waf/xss/

7
3
0

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
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?