オリジンとSOP(同一オリジンポリシー)について理解する
この記事について
CORS(Cross-Origin Resource Sharing)について完全に理解しようと思って記事を書き始めたのですが、CORSの前提でまず理解しなければいけない「オリジン」の意味だったりSOP(同一オリジンポリシー)について掘り下げているうちにめちゃくちゃ長くなってきました。
そのため、この記事ではオリジンやそれらにまつわる言葉の意味についてと、同一オリジンポリシーがどのようなもので、どういった制約を課しているのかを記述していきます。
CORSについては次の記事でまとめていきます。
オリジンとは?
というわけで、まずはOrigin(オリジン)から
ウェブコンテンツのオリジン (Origin) は、ウェブコンテンツにアクセスするために使われる URL の スキーム (プロトコル)、 ホスト (ドメイン)、 ポート番号 によって定義されます。スキーム、ホスト、ポート番号がすべて一致した場合のみ、 2 つのオブジェクトは同じオリジンであると言えます。
引用
https://developer.mozilla.org/ja/docs/Glossary/Origin
引用の通りですが、URLには「スキーム(プロトコル)」「ホスト(ドメイン)」「ポート」という要素があり、これら3つの組み合わせが**「オリジン」**と呼ばれているようです。
ドメインとの違い
オリジンがURLのことを指しているというのは文面から何となく理解できましたが、「ドメイン」とはどういった違いがあるの? ということが気になりました。
結論から言うと、オリジンとドメインは指しているものが以下のように違います。
- ドメイン(Domain): uenishi.blog
- オリジン(Origin): https://www.uenishi.blog:443
ドメインはオリジンの中の一部「uenishi.blog」を指しており、オリジンはプロトコル「https」とホスト(ドメイン)「www.uenishi.blog」、ポート番号「443」まで含んだものを指している、という点です。
httpsとは
ハイパーテキストトランスファープロトコル・セキュア(HTTPS)は、WebブラウザとWebサイト間でデータを送信するために使用される主要なプロトコルであるHTTPのセキュアバージョンです。HTTPSは、データ転送のセキュリティを強化するために暗号化されます。
https://www.cloudflare.com/ja-jp/learning/ssl/what-is-https/
ポート番号 443
HTTPSで使用されるポート番号。
ポート番号はコンピュータで実際に通信される出入口の番号のこと。各通信プロトコルによって番号が定められており、HTTPSでのやり取りは443番ポートを用いるように定められています。
HTTPでのやり取りは80番ポート、FTPは20・21番など、それぞれのプロトコルによって予約されており、それを「ウェルウンポート」と呼びます。
ポート番号は省略することができ、省略した場合は先頭で指定したプロトコルに対応したポート番号が使われます(HTTPSであれば、443とわざわざURLに打たずとも、ポート番号443が使用される)。
https://jp.globalsign.com/support/ssl/certificates/about-portno.html
URLの全体像についての図解は、以下が参考になったため引用させていただきます。

引用
https://shukapin.com/infographicIT/origin-policy
FQDN (Fully Qualified Domain Name)
ここは補足的な掘り下げになります。
MDNの引用より「ホスト(ドメイン)」と書いていた際、ホスト = ドメインのような印象を受けたので、改めて調べてみました。
厳密には全く別で、上記の図の通り、ホスト(www)とドメイン(aaa.com)を合わせてFQDNと呼ぶようです。
FQDNはFully Qualified Domain Nameの略で、「完全修飾ドメイン名」と訳されます。
今回、このあたりは掘り下げすぎず、端的にまとめます。
- FQDN
- ホスト名とドメイン名のこと。省略できるものを全部ちゃんと書いた形
- ホスト名
- ドメイン名の前に . で区切ってある。www.domain.comやnote.domain.com など(省略可能な場合もある)
- ドメイン名
- インターネット上での「住所」に相当する。ドメインは重複登録できず、世界中に一つしか存在しないため、基本的には早いもの勝ち。
クロスオリジンと同一オリジン
「オリジン」が何を指しているのかがはっきりしてきたところで、「クロスオリジン」という言葉に着目して掘り下げていこうと思います。
開いているWebページに対して、
- 異なるオリジン:クロスオリジン
- 同じリソース:同一オリジン
といい、オリジンを境界としてリソースの保護範囲を決定する取り決めを「同一オリジンポリシー(Same-Origin Policy)」と呼びます。
例として
- http://www.example.jp/index.html
- http://www.example.jp:80/index.ts
- https://www.example.jp/index.html
- http://www.example.com/index.js
上記の例では、1と2は
- スキーム → http://
- ホスト → www.example.jp
- ポート → 80 (1は省略されている)
であり、「同一オリジン」といえます。
その他1と3 & 4、2と3 & 4はオリジンが異なっており、1, 2から見るとそれぞれ「クロスオリジン」であるといえます。
同一オリジンポリシー(Same-Origin Policy)
「同一生成元ポリシー」や「同一源泉ポリシー」というような呼ばれ方もしますが、実際に指す意味合いとしては同じものです。
ブラウザに実装されている仕組みで、主にCSRF(クロスサイトリクエストフォージェリ)やXSS(クロスサイトスクリプティング)などといった攻撃を防止するためのものです。
具体的にはWebページなどで、異なるオリジンのリソースにアクセスできないよう制限します。
例えば以下のような場合

ネットサーフィンを楽しんでいるユーザーが、WebページAを開いている最中、ユーザーのローカルストレージになんらかの情報が保存されたとします。
そしてWebページAの次にアクセスしたサイトが悪意のあるサイトだった場合、サイトがローカルストレージにアクセスし、先ほどのデータをサーバーへ送信されるかもしれません。
このような攻撃を避けるために、あるWebリソースから別のWebリソースに対する操作には、なんらかの制限が必要になってきます。
しかし、全てのWebリソース間の操作に対して制限をかけてしまうと、Webの自由度や利便性が著しく下がってしまいます。そのため、Webブラウザは最低限、セキュリティが担保できる範囲内での制限にとどめています。
あるリソースから別のリソースに対して操作を行う時、以下の3つに分類できます。
- ブラウザ内アクセス
- ネットワーク越しのアクセス
- 埋め込み
これらを表にまとめると、以下になります。
| 操作 | 制限 |
|---|---|
| ブラウザ内アクセス | ほぼ禁止されている |
| ネットワーク越しのアクセス | 単純リクエストのみ許可。それ以外は制限される |
| 埋め込み | 制限なし |
ブラウザ内アクセス
ウィンドウへの参照を経由したDOMの操作など
例えば、以下のようなコードの場合。
<script> window.addEventListener("load", () => { alert(window.frame01.contentWindow.secret.innerHTML == "THIS IS A SECRET MESSAGE"); alert(window.frame02.contentWindow.secret.innerHTML == "THIS IS A SECRET MESSAGE"); });</script><iframe id="frame01" src="http://localhost:10000/chapter02/resource.html"></iframe><iframe id="frame02" src="http://localhost:20000/chapter02/resource.html"></iframe>http://localhost:10000/chapter02/read.htmlにあるファイルにアクセスした場合。
iframeで異なるOrigin(http://localhost:20000)のWebページにアクセスして、DOMを書き換えようとしています。
異なるOriginのリソースを書き換えてしまえたら、他のWebサイトを改ざんできてしまうこととなるため、これは妥当な制限と言えます。
エラー内容
Uncaught DOMException: Blocked a frame with origin "http://localhost:10000" from accessing a cross-origin frame. at http://localhost:10000/chapter02/read.html:4:40また、http://localhost:20000 のリソースがFetch APIなどで取得したデータ(レスポンス)に関しても、http://localhost:10000から読み出したりすることは制限がされます。