サニタイズとは?Vue3でのリッチテキストの安全な取り扱い方法
ウェブセキュリティの基石、サニタイズの重要性を解説。Vue3でのリッチテキストのサニタイズ方法とその実装例を紹介します。安全なウェブアプリケーション開発のための必読ガイド。
前提
- リッチテキストを扱うVue3プロジェクトが存在する
サニタイズとは?
サニタイズは、ユーザーからの入力データを安全に扱うためのプロセスです。具体的には、悪意のあるコードやスクリプトを含む可能性のある入力データをクリーンな形式に変換することを指します。サニタイズを行うことで、XSS攻撃などのセキュリティリスクを大幅に軽減することができます。
XSS攻撃の防止
サニタイズを行わないと、悪意のあるユーザーがスクリプトを埋め込むことができ、そのスクリプトが他のユーザーのブラウザで実行される可能性があります。これにより、ユーザーのデータが盗まれる、ウェブサイトが改ざんされるなどのリスクが生じます。
法的・規制上のリスクの軽減
ユーザーのデータを適切に保護しない場合、データ保護法やプライバシー法に違反する可能性があります。サニタイズを行うことで、これらの法的リスクを軽減することができます。
信頼性の確保
サニタイズを適切に行うことで、ウェブサイトやアプリケーションの信頼性を維持・向上させることができます。ユーザーは、安全に情報を共有・閲覧できるプラットフォームを好む傾向があります。
XSS(クロスサイトスクリプティング)攻撃
XSS攻撃は、ウェブアプリケーションの脆弱性を悪用して、悪意のあるスクリプトを他のユーザーのブラウザ上で実行させる攻撃手法です。攻撃者は、ウェブページにスクリプトを埋め込むことで、他のユーザーの情報を盗んだり、ユーザーに偽の操作をさせたりすることができてしまいます。
Vue3で懸念されている最たるものが v-html
です。
静的サイトでの利用や、管理者のみが扱う場合には(自分は)スルーしてますが、v-htmlが非推奨とされている通り、扱いには十分な配慮が必要です。
現在の実装
以前簡単に書いたコードです。
https://github.com/yutahhh/firebase-study/tree/feature/%238
<template>
<div>
<v-container>
<v-row>
<v-col
cols="12"
md="8"
>
<v-card
class="color-pallet h-100"
>
<v-card-text>
<div v-html="richText" />
</v-card-text>
<v-card-actions>
<v-btn
color="#08ffc8"
@click="switchColor='cool'"
>
クール系
</v-btn>
<v-btn
color="#ffb6b9"
@click="switchColor='cute'"
>
かわいい系
</v-btn>
</v-card-actions>
</v-card>
</v-col>
<v-col
cols="4"
class="d-none d-md-block"
>
<v-card
title="ペットの冒険"
subtitle="ここから下の画像が追従するよ"
class="mb-8"
/>
<v-card class="sidebar-sticky">
<v-img src="https://placekitten.com/300/300" />
</v-card>
</v-col>
</v-row>
</v-container>
</div>
</template>
<script setup lang="ts">
# 省略
const richText = `
<h1>ペットの冒険</h1>
<h2>うちのペット</h2>
<p>こんにちは、みんな!私の家にはかわいいペットがいるんだ。名前はミケとポチ。ミケは黒猫で、ポチは元気な犬だよ。一緒に遊ぶのが大好きで、家族みんなで楽しい時間を過ごしているんだ。</p>
<h2>冒険の始まり</h2>
<p>ある日、ミケとポチは一緒に冒険に出かけることになったんだ。ミケは猫なのに、なんだか冒険者みたいな気分になるんだよ。</p>
<h3>森への旅</h3>
<p>まずは森へ行ってみることにしたよ。木々の間をくぐり抜けながら歩くと、鳥のさえずりが聞こえてきてとっても心地よかった。ポチはワンワンと元気に駆け回って、私たちを楽しませてくれたんだ。</p>
<h3 class="highlight">川での出来事</h3>
<p>森を抜けると、きれいな川が広がっていたんだ。ミケは初めての水辺に興味津々で近づいていったよ。すると、ミケがジャンプして川に飛び込んでしまったんだ!でも大丈夫、私たちはすぐに助けてあげたんだ。ミケはびしょ濡れになっちゃったけれど、みんなで笑っていたよ。</p>
<h3>大冒険の終わり</h3>
<p>冒険は楽しい思い出と共に終わったんだけれど、ミケとポチはいつも一緒にいるから、これからもたくさんの冒険が待っていると思うんだ。ペットとの冒険は最高だね!</p>
<p>それではまたね!</p>
`
</script>
<style lang="sass">
# 省略
</style>
ここにサニタイズ対応を挟んで改修します。
改修
sanitize-html
を使用して、でリッチテキストをサニタイズしていきます。
1. まず、sanitize-html
をインストールします。(yarn)
$ yarn add sanitize-html
# typescriptの場合は以下も入れます
$ yarn add @types/sanitize-html -D
2. 次に、コンポーネントの<script>
セクションにsanitize-html
をインポートし、リッチテキストのサニタイズを行います。
<script setup lang="ts">
import sanitizeHtml from 'sanitize-html';
// ... その他のコード ...
// サニタイズ設定
const sanitizeOptions = {
allowedTags: ['h1', 'h2', 'h3', 'p', 'img'],
allowedAttributes: {
'img': ['src', 'alt'] // デフォルトでもonerrorなどのイベントハンドラは許可していないが、明示的に。
}
}
// リッチテキストのサニタイズ
const xssText = `<p>攻撃を仕掛けるテキスト</p><img src="存在しない画像" onerror="alert('XSS攻撃!')" />`
</script>
3. 最後に、<template>
セクションのv-html
ディレクティブを更新して、サニタイズされたテキストを使用します。
<div v-html="sanitizeHtml(xssText, sanitizeOptions)" />
共有
こちらに動作環境があります。
https://study.theblueback.com/
※ 既存の実装と合わせるため、ちょっと変えてます。ハリボテですが「XSS攻撃」ボタンで検証できるようにしています。
【今回の作業ブランチ】
https://github.com/yutahhh/firebase-study/tree/feature/%2311
お疲れ様でした。