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>
ここまでお読みいただきありがとうございました!