#100　Vue 3でBlobを使ってみた

## はじめに
Vue 3でBlobを使用する機会があったので記事にしました。
Blobの使用に伴い、CSP（コンテンツセキュリティポリシー）の設定を変更しなければならない場合があったため、CSPについても触れていきたいと思います。

### Blob（Binary Large Object）とは

Blobは、ブラウザ内で画像、音声、動画、テキストなどバイナリデータを扱うことができるオブジェクトです。サーバーとの通信を行わずメモリ上で、ファイルのようにデータを保持・操作することができます。

### Vue 3でのBlobを使ってみる

#### 画像ファイルをアップロードして表示する
Blobを使って画像ファイルをアップロード、プレビュー表示させてみます。

```vue:vue
<template>
  <div>
    <!-- ファイル選択用 -->
    <input type="file" @change="onFileChange" />
    
    <!-- 画像URLが存在する場合、画像を表示する -->
    <img v-if="imageUrl" :src="imageUrl" alt="Uploaded Image" />
    
    <!-- 画像が存在する場合、削除ボタンを表示する -->
    <button v-if="imageUrl" @click="removeImage">削除</button>
  </div>
</template>

<script>
import { ref, watch } from 'vue';

export default {
  setup() {
    const imageUrl = ref(null);

    // ファイル選択時に実行
    const onFileChange = (event) => {
      const file = event.target.files[0]; // 選択されたファイルを取得
      if (file) {
        const reader = new FileReader(); // FileReaderのインスタンスを作成
        reader.onload = (e) => {
          // 読み込み完了時にURLを生成してimageUrlに設定
          imageUrl.value = URL.createObjectURL(new Blob([e.target.result], { type: file.type }));
        };
        reader.onerror = (error) => {
          console.error("ファイルが読み込めません", error);
        };
        reader.readAsArrayBuffer(file);
      }
    };

    // 画像削除時に実行
    const removeImage = () => {
      if (imageUrl.value) {
        URL.revokeObjectURL(imageUrl.value); // 使わなくなったURLを解放する
      }
      imageUrl.value = null; // 画像URLをリセット
    };

    // 画像URLに変更があったとき実行
    watch(imageUrl, (newUrl, oldUrl) => {
      if (oldUrl) {
        URL.revokeObjectURL(oldUrl); // 使わなくなったURLを解放
      }
    });

    return { imageUrl, onFileChange, removeImage }; // テンプレートで使用するデータとメソッドを返す
  }
};
</script>

```
↓ 画像ファイル選択前
<img src='https://www.nxted.co.jp/blog/img/105/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%202024-09-20%20122327.png' width="30%">

↓ 画像ファイル選択後
<img src='https://www.nxted.co.jp/blog/img/105/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%202024-09-20%20143857.png' width="30%">

実際の画面はこのような動きです。

#### WEBアプリでBlobを使用する際の注意点
WEBアプリのセキュリティが厳しい場合、Blob URLがブロックされることがあります。
Blob URLを使って画像やファイルをブラウザで表示したりダウンロードしたりする場合は、CSPヘッダーで blob: を許可する必要があるからです。

### CSP（Content Security Policy）とは
CSPは、Webアプリが外部リソースを安全に読み込のセキュリティ対策です。信頼できるソースからのリソースのみを許可して、XSS（クロスサイトスクリプティング）などの攻撃からアプリケーションを守ることができます。

#### Blob使用時のCSPの設定
例えば下記のようにCSPヘッダーに `blob:` を追加しBlobの使用を許可します。

```http:http
Content-Security-Policy: default-src 'self'; img-src 'self' blob:; script-src 'self' 'unsafe-inline';
```

#### 説明
```
default-src 'self'
```
デフォルトのリソースの読み込み元を自分自身のドメインに限定します。
```
img-src 'self' blob:
```
画像のソースに自分自身のドメインとBlob URLを使用できます。
```
script-src 'self' 'unsafe-inline
```
スクリプトのソースに自分自身のドメインとインラインスクリプトを使用できます。

他にも設定項目があるので、アプリの用途に合ったセキュリティ設定にしてください。

#### ブラウザからCSP設定を確認する
該当のページで開発者ツールを開き、「Network」タブでリソースを読み込んでいるリクエストを選択します。
リクエストの「Headers」＞「Response Headers」から、Content-Security-Policy ヘッダーを確認することができます。

#### エラーが起きた時
CSPのエラーは開発者ツールのコンソールに表示されます。
既述したように、Blob URLの使用を許可するためには、img-src や media-src に blob: を追加する必要があります。
セキュリティ面を考慮しつつ必要なリソースの読み込みができるよう、CSP設定を見直しましょう。

### まとめ
今後もBlobを使った操作やSCPについて理解を深めていきたいです。
ご覧いただきありがとうございました。

出典：
https://developer.mozilla.org/en-US/docs/Web/API/Blob
https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP