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