見出し画像

Canvas要素とCORS設定 #436

S3からCloudfrontで動画を配信してアプリケーションで再生する場合、単に再生するだけならCORSの設定は不要なのに、動画データをCanvas要素に描画する(プログラム的に実行するスクショ等)にはCORSの設定が必要でした。

この違いがよく分かっていなかったので整理してみました。

CORSとは何か?

CORS(Cross-Origin Resource Sharing)は、ウェブページのオリジン(スキーマ、ホスト、ポート)が異なる別のオリジンからリソースを安全に取得できるようにするための機構です。

ブラウザの同一オリジンポリシーにより、スクリプトが異なるオリジンからのリソースにアクセスすることは制限されていますが、CORSはこの制限を特定の条件下で緩和します。

なぜ動画の再生だけなら問題ないのか?

一般に、ブラウザでの動画や画像のようなメディアリソースの読み込みと再生は、同一オリジンポリシーの厳格な制限を受けません。つまり、あるオリジンのウェブページから別のオリジンにホストされた動画を直接 <video> タグで読み込んで再生できます。

<video>
    <source [src]="videoUrl" type="video/mp4" />
</video>

なぜCanvasでの描画で問題が発生するのか?

しかし、Canvas要素に画像や動画を描画する場合、セキュリティの制約が発生します。

Canvas要素に異なるオリジンからのリソースを描画すると、Canvasは「汚染」されたとみなされます。汚染されたCanvasからは、スクリプトを使ってピクセルデータを読み出すことができません(例:toDataURL や toBlob メソッドの使用)。

これはクロスサイトスクリプティング(XSS)攻撃を防ぐためのセキュリティ対策によるものです。

どうしたらCanvasに描画できるようになるか?

結論としては以下2つの対応が必要です。

  • クライアントサイド(HTML):外部リソースをフェッチする際のCORSポリシーの適用を設定

  • サーバーサイド:CORSを設定する

なぜクライアントサイドの設定が必要か?

ここではHTMLのvideoタグにcrossorigin="anonymous" 属性を付与する必要があります。

この属性は、HTML要素(<video>, <img>, <script> など)が外部のリソースを読み込む際のCORSポリシーを制御し、外部のリソースをクレデンシャル(例: クッキーやHTTP認証情報)なしで取得することを指示します。

<video crossorigin="anonymous">
    <source [src]="videoUrl" type="video/mp4" />
</video>

しかしCanvasに描画された外部リソースからのデータを安全に読み出すためには、そのリソースがCORSポリシーに準拠している必要があります。↓

なぜサーバーサイドのCORS設定が必要か?

サーバーサイド(例: S3やCloudFront、ウェブサーバー)でのCORS設定は、外部ドメインからのリクエストをどのように扱うかを定義します。

今回のケースでは、サーバーサイドにあたるS3バケットとCloudFrontディストリビューションにCORS設定を施します。以下のヘッダーなどです。

  • Access-Control-Allow-Origin:許可されるオリジン

  • Access-Control-Allow-Methods:許可されるHTTPメソッド

  • Access-Control-Allow-Headers:許可されるヘッダー

これらのヘッダーは、外部ドメインからのリクエストが受け入れられるかどうか、またどのような条件で受け入れられるかをブラウザに伝えます。

ここで異なるオリジンからのリソース(この場合、S3からホストされた動画)に Access-Control-Allow-Originが含まれる場合、そのリソースはCORSポリシーに従って安全に使用できるとみなされます。

このようにして異なるオリジンからの動画をCanvasに描画してもCanvasが汚染されないようにし、Canvasの内容を安全に操作できるようになります。

なぜ両方の設定が必要か?

HTML要素で crossorigin="anonymous" を設定しても、対象のリソースを提供するサーバーが適切なCORSヘッダーを含めていない場合、ブラウザはそのリソースの利用をブロックします(特にセキュリティに敏感な操作、例えばCanvasでのピクセルデータの読み出しの際)。

逆に、サーバーがCORSヘッダーを提供していても、HTML要素が適切な crossorigin 属性を持っていない場合、ブラウザはリソースの使用を制限する場合があります

したがって、外部リソースを安全に利用するためには、HTML文書内での crossorigin 属性の設定と、サーバーサイドでのCORSポリシーの設定の両方が重要です。

ついでに

HTML上の動画がダウンロードされるのを防ぐために以下の設定が可能です。

controlsList="nodownload"属性でダウンロードを無効化
oncontextmenu="return false;"で右クリックでの操作を無効化

<video
  controls
  controlsList="nodownload"
  crossorigin="anonymous"
  oncontextmenu="return false;"
>
    <source [src]="videoUrl" type="video/mp4" />
</video>


ここまでお読みいただきありがとうございました!

参考


この記事が気に入ったらサポートをしてみませんか?