tl; dr —関連する部分を見つけやすくするために、回答の最後に見出しと見出しがあります。すべてを読むことをお勧めしますが、さまざまな状況でどのように適用されるかを簡単に理解できるようにする理由を理解するのに役立つ背景が提供されるためです。
同一生成元ポリシーについて
これは同一生成元ポリシーです。これは、ブラウザによって実装されるセキュリティ機能です。
あなたの特定のケースは、それがXMLHttpRequestにどのように実装されているかを示しています(そして、フェッチを使用すると同じ結果が得られます)だけでなく、他のものにも適用されます(に読み込まれた画像<canvas>
やに読み込まれたドキュメントなど<iframe>
)。わずかに異なる実装。
(奇妙なことに、それはCSSフォントにも適用されますが、それは、ファウンドファウンドリがDRMを主張し、Same Origin Policyが通常カバーするセキュリティ問題のためではないためです)。
SOPの必要性を示す標準的なシナリオは、3つのキャラクターで示すことができます。
- アリスはウェブブラウザを持っている人です
- ボブはウェブサイトを運営しています(
https://www.[website].com/
あなたの例では)
- マロリー
http://localhost:4300
はあなたの例でウェブサイトを運営します
アリスはボブのサイトにログインしており、そこにいくつかの機密データがあります。おそらく、会社のイントラネット(LAN上のブラウザーにのみアクセス可能)、または彼女のオンラインバンキング(ユーザー名とパスワードを入力した後に取得したCookieを使用してのみアクセス可能)でしょう。
アリスは、アリスのブラウザにボブのウェブサイトへのHTTPリクエスト(彼女のIPアドレスからクッキーなど)を実行させるJavaScriptを含むマロリーのウェブサイトを訪問します。これは使用するのと同じくらい簡単かもしれませんXMLHttpRequest
、responseText
です。
ブラウザの同一生成元ポリシーにより、ボブのWebサイトから返されたデータ(ボブとアリスがマロリーにアクセスさせたくない)がJavaScriptで読み取られなくなります。(たとえば、画像<img>
のコンテンツがJavaScript(またはマロリー)に公開されていないため、要素全体を使用して画像を表示できることに注意してください。キャンバスをミックスにスローしない限り、同じオリジンを生成します。違反エラー)。
なぜ同じ起源のポリシーが適用されないと思われるときに適用されるのか
特定のURLでは、SOPが不要な場合があります。これが当てはまるいくつかの一般的なシナリオは次のとおりです。
- アリス、ボブ、マロリーは同じ人物です。
- ボブは完全に公開情報を提供しています
…しかし、ブラウザは上記のいずれかが真であるかどうかを知る方法がないため、信頼は自動的ではなく、SOPが適用されます。ブラウザーが別のWebサイトに与えられたデータを提供する前に、明示的に許可を与える必要があります。
同一生成元ポリシーがWebページのJavaScriptにのみ適用される理由
ブラウザ拡張機能*
、ブラウザ開発者ツールの[ネットワーク]タブ、Postmanなどのアプリケーションは、インストールされたソフトウェアです。あるWebサイトから別のWebサイトにアクセスしたため、別のWebサイトに属するJavaScriptにデータを渡していない。ソフトウェアのインストールは通常、より意識的な選択を行います。
リスクがあると考えられる第三者(Mallory)は存在しません。
*
ブラウザーの拡張機能は、クロスオリジンの問題を回避するために慎重に作成する必要があります。例については、Chromeのドキュメントを参照してください。
JSを使用せずにページにデータを表示できる理由
マロリーのサイトがブラウザにサードパーティからデータをフェッチして表示できる状況がいくつかあります(たとえば<img>
、画像を表示する要素を追加することによって)。ただし、MalloryのJavaScriptがそのリソースのデータを読み取ることはできません。これを行うことができるのは、AliceのブラウザーとBobのサーバーだけなので、依然として安全です。
CORS
Access-Control-Allow-Origin
HTTPの応答エラーメッセージで参照さヘッダはの一部であるCORSボブが明示的にアリスのブラウザを介してアクセスするマロリーのサイトへのデータのアクセス許可を付与することを可能にする標準。
基本的な実装には、次のものが含まれます。
Access-Control-Allow-Origin: *
…応答ヘッダーで、任意のWebサイトがデータを読み取ることを許可します。
Access-Control-Allow-Origin: http://example.com/
…特定のサイトのみにアクセスを許可し、ボブはリクエストに基づいて動的に生成できますOrigin
ヘッダーにすべてではなく複数のサイトにアクセスを許可できます。
Bobがその応答ヘッダーを設定する方法の詳細は、BobのHTTPサーバーまたはサーバー側プログラミング言語、あるいはその両方によって異なります。あり、様々な一般的な構成のためのガイドのコレクションそのかもしれないのヘルプが。
注意:一部のリクエストは複雑で、ブラウザがJSの要求するGET / POST / PUT / Whateverリクエストを送信する前にサーバーが応答する必要があるプリフライト OPTIONSリクエストを送信します。Access-Control-Allow-Origin
特定のURLにのみ追加するCORSの実装は、多くの場合、これによって作動します。
CORSを介してアクセス許可を付与することは、ボブが次のいずれかの場合にのみ行うことです。
- データは非公開ではありませんでした か
- マロリーは信頼された
しかし、私はボブではありません!
マロリーがこのヘッダーを追加するための標準的なメカニズムはありません。ボブのWebサイトから取得する必要があるためです。
BobがパブリックAPIを実行している場合は、CORSをオンにするメカニズムが存在する可能性があります(おそらく、リクエストを特定の方法でフォーマットするか、Bobのサイトの開発者ポータルサイトにログインした後で構成オプションを使用します)。ただし、これはボブが実装するメカニズムでなければなりません。マロリーは、ボブのサイトにあるドキュメントを読んで何か入手できるかどうかを確認したり、ボブと話し合ってCORSの実装を依頼したりできます。
「プリフライトへの対応」に関するエラーメッセージ
一部のクロスオリジンリクエストはプリフライトされています。
これは、(大まかに言えば)次のようなクロスオリジン要求を行おうとすると発生します。
- Cookieなどの資格情報が含まれています
- 通常のHTMLフォームでは生成できませんでした(たとえば、フォームので使用できないカスタムヘッダーまたはContent-Typeがあります
enctype
)。
プリフライトが必要なことを正しく行っている場合
これらの場合でも、この回答の残りの部分は引き続き適用されますが、サーバーがプリフライトリクエストをリッスンできることを確認する必要があります(これはOPTIONS
(ではなく)GET
、POST
または送信しようとしていたものは何でも)、適切に応答します。Access-Control-Allow-Origin
ヘッダーだけでなくAccess-Control-Allow-Methods
、Access-Control-Allow-Headers
特定のHTTPメソッドやヘッダを許可します。
誤ってプリフライトをトリガーしている場合
Ajaxリクエストを作成しようとするときに、人は時々間違いを犯し、時にはそれがプリフライトの必要性を引き起こします。APIがクロスオリジンリクエストを許可するように設計されているが、プリフライトを必要とするものを何も必要としない場合、これはアクセスを破壊する可能性があります。
これを引き起こす一般的な間違いは次のとおりです。
- 入れよう
Access-Control-Allow-Origin
リクエストに他のCORS応答ヘッダーをます。これらはリクエストに属しておらず、役立つことは何もせず(自分に権限を付与できる権限システムのポイントは何ですか?)、応答にのみ表示される必要があります。
Content-Type: application/json
内容を説明するリクエストボディのないGETリクエストにヘッダーを付けようとしている(通常、作成者がとを混同Content-Type
している場合Accept
)。
これらのいずれの場合でも、追加のリクエストヘッダーを削除するだけでプリフライトが不要になることがよくあります(これにより、シンプルリクエストをサポートするがプリフライトリクエストをサポートしないAPIと通信するときに問題が解決します)。
不透明な反応
場合によっては、HTTPリクエストを作成する必要がありますが、応答を読み取る必要はありません。たとえば、ログメッセージをサーバーに投稿して記録する場合などです。
(ではなく)APIを使用しているfetch
場合は、XMLHttpRequest
CORSを使用しないように構成できます。
これでは、CORSが実行する必要があることは何もできないことに注意してください。応答を読み取ることができなくなります。プリフライトが必要なリクエストを行うことはできません。
シンプルなリクエストを作成し、レスポンスを表示せず、開発者コンソールにエラーメッセージを入力しません。
その方法はfetch
、CORS を使用してリクエストを作成し、そのレスポンスを表示する権限を取得していないときに表示されるChromeエラーメッセージで説明されています。
CORSポリシーによって、 ' https://example.com/
'からの' ' でのフェッチへのアクセスhttps://example.net
がブロックされました:Access-Control-Allow-Origin
要求されたリソースに' 'ヘッダーがありません。不透明な応答でニーズが満たされる場合は、リクエストのモードを「no-cors」に設定して、CORSを無効にしてリソースをフェッチします。
したがって:
fetch("http://example.com", { mode: "no-cors" });
CORSの代替
JSONP
ボブは、JSONPのようなハックを使用してデータを提供することもできます。これは、CORSが登場する前に人々がAjaxをクロスオリジンで作成した方法です。
これは、データをマロリーのページに挿入するJavaScriptプログラムの形式でデータを提示することによって機能します。
マロリーはボブが悪意のあるコードを提供しないことを信頼する必要があります。
共通のテーマに注意してください。データを提供するサイトは、サードパーティのサイトがブラウザに送信しているデータにアクセスしても問題ないことをブラウザに伝える必要があります。
JSONPは、<script>
要素を追加して、ページ内の既存の関数を呼び出すJavaScriptプログラムの形式でデータを読み込むことで機能するため、JSONを返すURLでJSONPテクニックを使用しようとすると、通常はCORBエラーで失敗します。 JavaScriptではありません。
2つのリソースを単一のオリジンに移動します
JSが実行されるHTMLドキュメントと要求されたURLが同じオリジン(同じスキーム、ホスト名、およびポートを共有する)上にある場合、それらの同じオリジンポリシーはデフォルトでアクセス許可を付与します。CORSは必要ありません。
プロキシ
マロリーは、サーバー側のコードを使用してデータをフェッチすることができます(データは、通常どおり、サーバーからHTTP経由でアリスのブラウザに渡すことができます)。
次のいずれかになります。
- CORSヘッダーを追加する
- 応答をJSONPに変換する
- HTMLドキュメントと同じオリジンに存在する
そのサーバー側コードは、サードパーティ(CORS Anywhereなど)によって記述およびホストされる可能性があります。これによるプライバシーの影響に注意してください。サードパーティは、サーバー全体で誰が何をプロキシするかを監視できます。
ボブはそれが起こるためにどんな許可も与える必要はないでしょう。
それはマロリーとボブの間だけなので、ここではセキュリティへの影響はありません。ボブがマロリーがアリスであると考え、マロリーにアリスとボブの間で秘密にしておくべきデータを提供する方法はありません。
その結果、マロリーはこの手法を使用して公開を読むことができますデータ。
ただし、他の誰かのWebサイトからコンテンツを取得して自分で表示することは、著作権の侵害となり、訴訟を起こす可能性があることに注意してください。
Webアプリ以外のものを書く
「同一生成元ポリシーがWebページのJavaScriptにのみ適用される理由」で説明したように、WebページにJavaScriptを記述しないことでSOPを回避できます。
JavaScriptとHTMLを使い続けることができないという意味ではありませんが、Node-WebKitやPhoneGapなどの他のメカニズムを使用して配布することができます。
ブラウザ拡張
同一生成元ポリシーが適用される前に、ブラウザ拡張が応答にCORSヘッダーを挿入する可能性があります。
これらは開発には役立ちますが、本番サイトには実用的ではありません(サイトのすべてのユーザーに、ブラウザのセキュリティ機能を無効にするブラウザ拡張機能をインストールするよう要求するのは無理です)。
また、単純なリクエストでのみ機能する傾向があります(プリフライトOPTIONSリクエストを処理するときに失敗します)。
通常、ローカル開発サーバーで適切な開発環境を用意することをお勧めします。
その他のセキュリティリスク
SOP / CORSは、個別に処理する必要があるXSS、CSRF、またはSQLインジェクション攻撃を軽減しないことに注意してください。
概要
- 他の誰かのサーバーへのCORSアクセスを可能にするクライアント側のコードでできることは何もありません。
- サーバーを制御する場合、要求は次のように行われます。CORS権限をサーバーに追加します。
- あなたがそれを制御する人と友好的である場合:CORS権限を追加するように彼らに依頼してください。
- 公共サービスの場合:
- APIドキュメントを読んで、クライアント側のJavaScriptでAPIにアクセスすることについての彼らの意見を確認してください。
- 彼らはあなたに特定のURLを使うように言うかもしれません
- 彼らはJSONPをサポートするかもしれません
- クライアント側コードからのクロスオリジンアクセスをまったくサポートしていない可能性があります(これは、特に各リクエストでパーソナライズされたAPIキーを渡す必要がある場合、セキュリティ上の理由で意図的な決定となる場合があります)。
- 不要なプリフライトリクエストをトリガーしていないことを確認してください。APIは、単純なリクエストには権限を付与しますが、プリフライトされたリクエストには付与しません。
- 上記のいずれにも当てはまらない場合:代わりにブラウザーにサーバーと通信させ、サーバーに他のサーバーからデータをフェッチして渡します。(CORSヘッダーを、ユーザーが使用できる公的にアクセス可能なリソースに添付するサードパーティのホスティングサービスもあります)。