😚

オリジン(Origin)とCORSの関係を学ぶ

2023/04/18に公開

概要

先日、フロントエンド開発のためのセキュリティ入門 知らなかったでは済まされない脆弱性対策の必須知識という良書の中の良書と出会ってしまったので、その際に学んだことのメモです。

youtubeもあるので、ぜひ見てください。

フロントエンド開発(JS)を行なっているとXMLHttpRquestFetch APIを使った際などによくcorsのエラーに出くわすことがあります。
毎回邪魔者扱いしていたcorsエラーですが、あまり深く考えたことがなかったので、今回はoriginとcorsの関係についてざっくりと学んでみようと思います。

Originとは

ウェブのオリジン (Origin) は、ウェブコンテンツにアクセスするために使われる URL の スキーム (プロトコル)ホスト (ドメイン)ポート番号 によって定義され、スキーム、ホスト、ポート番号がすべて一致した場合のみ、 2 つのオブジェクトは同じオリジンであると言える。

スキーム(scheme): 通信プロトコルを示す部分で、一般的には httphttps の部分のこと
ホスト(host): ドメイン名やサブドメイン名を含むウェブサイトのアドレス。例えば、example.comsubdomain.example.com など。
ポート(port): ウェブサーバーがリッスンしているポート番号。

⭕️ HTTP コンテンツを配信するのに既定で 80 番ポートを使うため、以下は同一オリジンと言える。
http://example.com/path/to
http://exemple.com:80

❌ 以下はスキームが異なるので同一オリジンではない。
https://example.com/
http://example.com/

❌ 以下はポートが異なるため同一オリジンではない。
https://example.com:443
https://example.com:8080

同一オリジンポリシー

同一オリジンポリシー(Same-Origin Policy)は、ウェブブラウザのセキュリティモデルであり、異なるオリジンからのリソースへのアクセスを制限する役割を果たしている。 つまり、ブラウザは一部のデータのやり取りを同一のオリジンだけに制限している。 これにより、悪意のあるウェブサイトが、別のオリジンのリソースにアクセスして情報を盗み取ることを防ぐことができる。
また、クロスサイトスクリプティング(XSS)攻撃など、異なるオリジンのWebページからのスクリプトの実行を制限することで、XSS攻撃を防ぐことができる。
同一オリジンポリシーは主に、他のオリジンからの悪意のあるスクリプトがデータにアクセスしたり、盗んだりすることを防ぐ役割がある。

同一オリジンポリシーの制限対象(一部)

・JSでの非同期通信
XMLHttpRequestやFetch APIなどでの異なるオリジンからのリクエストを制限する。

・Web Storage (localStorage および sessionStorage), Indexed DB
異なるオリジン間でのWebStrageへのアクセスを制限する。

・Canvas
異なるオリジンの画像をCanvasに描画しようとすると、Canvasが汚染され、データへのアクセスが制限される。

同一オリジンポリシーの非制限対象(一部)

同一オリジンポリシーだが、全てのアクセスが制限されるわけではなく、対象とならないものも当然ある。

<img>で読み込まれた画像
<video><audio> タグで読み込まれたメディアファイル
<iframe><frame>での別サイトコンテンツの読み込み
CSS&スクリプト
  異なるオリジンのCSSファイルやスクリプトファイルを読み込んで適用することが可能。
リンク
  異なるオリジンのウェブページへのリンクは自由に作成できる。

Cross Origin Resource Sharing(CORS, コルス)

同一オリジンポリシーは、サイトのセキュリティを確保するのにかなり重要な役割を果たしているが、信頼できるウェブサイトからのリクエストも制限してしまう。

例えば、同じ会社で複数のサイトを運営していたとしたら、それらのサイトからはアクセスを制限したくないといったことはよくあります。

その際に使われるのが、CORSである。
CORSを使えば、
信頼しているオリジンからのリクエストを許可することができ、クロスオリジンでのデータのやり取りが実現できる。
・JSのFetch APIやXHRなどの非同期通信でクロスオリジンからのデータのやりとりも可能。

'allowed_origins' => ['https://example.com']

APIで使っている言語のフレームワークでは、上記のようにCORSの制限を設定することができると思われる。

'allowed_origins' => ['*']

デフォルトで*となっており、全てのオリジンからのリクエストを許可している場合もあるが、セキュリティ的にはよろしくないとされている。

CORSの仕組み

CORSの仕組みはざっくりと以下のようになっている。

COR仕組み

クロスオリジンでのリクエストはクロスオリジンCORSで許可されていない場合、レスポンスがブラウザで破棄される仕組みになっている。

こういった仕組みから同一オリジンポリシーは、データを取得するのを防ぐ目的なら問題ないが、データの更新、削除といったサーバーの操作は、ブラウザがレスポンスを破棄しているだけであって、クロスオリジンのサーバーでの削除、更新処理は動いてしまっているので、制御することができないといった課題がある。

プリフライトリクエスト

上記のような課題は完全には、防ぐことができないので、削除、更新と言った処理は認証などのロジックを組み込むのは必須であると思われる。

ブラウザにはプリフライトリクエストといって、「リクエストを送信して大丈夫か?」といったことを確認するリクエストを送信する時がある。
これはブラウザによって自動的に行われるリクエストであり、特定の条件下でのみ行われるリクエストである。
プリフライトリクエスト

条件
・クロスオリジンリクエストが、GET、HEAD、POST 以外の HTTP メソッドを使用している。
・POST メソッドを使用するクロスオリジンリクエストで、Content-Type ヘッダーが application/x-www-form-urlencoded、multipart/form-data、または text/plain 以外の値を持っている。
・クロスオリジンリクエストにカスタムヘッダーが含まれている。

参考
・フロントエンド開発のためのセキュリティ入門 知らなかったでは済まされない脆弱性対策の必須知識

フロントエンド開発のためのセキュリティ入門 知らなかったでは済まされない脆弱性対策の必須知識 youtube

・mdn
・同一オリジンポリシーを理解する
・CORS: OPTIONSリクエスト(preflight request)を避ける

Discussion