web-dev-qa-db-ja.com

XMLHttpRequestはXXX No 'Access-Control-Allow-Origin'ヘッダーをロードできません

tl; dr;同一生成元ポリシーについて

Express.jsサーバーのインスタンスを開始するGruntプロセスがあります。これは、Chrome(最新バージョン)の開発者コンソールのエラーログに次のような空白のページが表示され始めたときまで、まったく問題なく機能していました。

XMLHttpRequestをロードできません https://www.example.com/ 要求されたリソースに「Access-Control-Allow-Origin」ヘッダーがありません。したがって、オリジン ' http:// localhost:43 'はアクセスを許可されていません。

ページへのアクセスを妨げるものは何ですか?

79

同一生成元ポリシーについて

これは Same Origin Policy です。これは、ブラウザによって実装されるセキュリティ機能です。

あなたの特定のケースは、XMLHttpRequestにどのように実装されているかを示しています(フェッチを使用する場合は同じ結果が得られます)が、他のものにも適用されます(<canvas>に読み込まれた画像や<iframe>に読み込まれたドキュメントなど)、実装がわずかに異なるだけです。

(奇妙なことに、CSSフォントにも適用されますが、ファウンドリがDRMを主張しており、Same Origin Policyが通常カバーするセキュリティの問題ではないためです)。

SOPの必要性を実証する標準シナリオは、 文字 で実証できます。

  • アリスはウェブブラウザを持っている人です
  • ボブはWebサイトを実行します(例ではhttps://www.[website].com/
  • MalloryはWebサイトを実行します(例ではhttp://localhost:4300

アリスはボブのサイトにログインし、そこにいくつかの機密データがあります。おそらく、会社のイントラネット(LAN上のブラウザーのみがアクセス可能)、または彼女のオンラインバンキング(ユーザー名とパスワードを入力した後に取得するCookieでのみアクセス可能)です。

アリスは、アリスのブラウザがボブのウェブサイトにHTTPリクエストを行う原因となるJavaScriptを備えたマロリーのウェブサイトにアクセスします(彼女のIPアドレスからクッキーなどを使用)。これは、XMLHttpRequestを使用してresponseTextを読み取るのと同じくらい簡単です。

ブラウザのSame Origin Policyは、BobのWebサイト(BobとAliceがMalloryにアクセスさせたくない)から返されたデータをJavaScriptが読み取れないようにします。 (たとえば、画像のコンテンツがJavaScript(またはMallory)に公開されていないため、<img>要素を使用して画像を表示できることに注意してください...キャンバスをミックスにスローしない限り、 willは、同一生成元違反エラーを生成します)。


必要と思わない場合に同一起源ポリシーが適用される理由

任意のURLについて、SOPが不要になる可能性があります。この場合の一般的なシナリオは次のとおりです。

  • アリス、ボブ、マロリーは同じ人物です。
  • ボブは完全に公開情報を提供しています

…しかし、ブラウザは上記のいずれかが真であるかどうかを知る方法がないため、信頼は自動的ではなく、SOPが適用されます。ブラウザが別のWebサイトに与えられたデータをブラウザが与える前に、許可を明示的に付与する必要があります。


同一生成元ポリシーがWebページのJavaScriptにのみ適用される理由

ブラウザ拡張機能、ブラウザ開発者ツールの[ネットワーク]タブ、およびPostmanなどのアプリケーションはインストール済みソフトウェアです。あるWebサイトから別のWebサイトに属するJavaScriptにデータを渡していないのは、その別のWebサイトにアクセスしたからです。通常、ソフトウェアのインストールにはより意識的な選択が必要です。

リスクと見なされる第三者(Mallory)はありません。


JSで読み取らずにページにデータを表示できる理由

Malloryのサイトがブラウザに第三者からデータを取得させて表示させる多くの状況があります(例えば、画像を表示する<img>要素を追加することにより)。 MalloryのJavaScriptがそのリソースのデータを読み取ることはできませんが、AliceのブラウザーとBobのサーバーのみがそれを実行できるため、安全です。


CORS

エラーメッセージで参照されているAccess-Control-Allow-Originヘッダーは CORS 標準の一部であり、BobはMalloryのサイトに明示的にアクセスを許可して、Aliceのブラウザー経由でデータにアクセスできます。

基本的な実装には次のものが含まれます。

Access-Control-Allow-Origin: *

…Webサイトがデータを読み取ることを許可するため。

Access-Control-Allow-Origin: http://example.com/

…特定のサイトのみがアクセスできるようにし、Originrequestヘッダーに基づいて動的に生成し、すべてではなく複数のサイトがアクセスできるようにします。

その応答ヘッダーの設定方法の詳細は、BobのHTTPサーバーやサーバー側のプログラミング言語に依存します。 さまざまな一般的な構成のガイドのコレクション が役立つ場合があります。

Model of where CORS rules are applied

NB:一部のリクエストは複雑であり、ブラウザがGET/POST/PUT/JSが作成したいリクエストを送信する前にサーバーが応答する必要がある preflight OPTIONSリクエストを送信します。 Access-Control-Allow-Originを特定のURLに追加するだけのCORSの実装は、多くの場合、これによって失敗します。


明らかに、CORSを介して許可を与えることは、ボブが次のいずれかの場合にのみ行うことです。

  • データはプライベートではありませんでしたまたは
  • マロリーは信頼された

このシナリオであなたもボブである場合、CORSパーミッションヘッダーを追加する方法の詳細は、選択したHTTPサーバーソフトウェアと、サーバー側プログラミングに使用している言語(ある場合)の組み合わせによって異なります。

Malloryはこのヘッダーを追加できません。ボブのサイトから許可を取得する必要があり、(SOPを役に立たなくするほど愚かな)自分に許可を与えることができる。


「プリフライトの応答」に言及するエラーメッセージ

一部のクロスオリジンリクエストは、 プリフライト です。

これは、(大まかに言えば)次のクロスオリジンリクエストを行おうとしたときに発生します。

  • Cookieなどの資格情報が含まれます
  • 通常のHTMLフォームでは生成できませんでした(たとえば、フォームのenctypeで使用できないカスタムヘッダーまたはContent-Typeがあります)。

プリフライトが必要なことを正しく行っている場合

これらの場合、この回答の残りはまだ適用されますが、サーバーがプリフライトリクエスト(OPTIONSになる)をリッスンできることを確認する必要もあります(GETPOST、または送信しようとしていたもの)ではなく、適切なAccess-Control-Allow-Originヘッダーで応答するだけでなく、特定のHTTPメソッドまたはヘッダーを許可するAccess-Control-Allow-MethodsおよびAccess-Control-Allow-Headersも応答します。

誤ってプリフライトをトリガーする場合

Ajaxリクエストを作成するときに人がミスをすることもあれば、プリフライトが必要になることもあります。 APIがクロスオリジンリクエストを許可するように設計されているが、プリフライトを必要とするものを必要としない場合、これによりアクセスが中断される可能性があります。

これを引き起こす一般的な間違いは次のとおりです。

  • Access-Control-Allow-Originおよび他のCORS応答ヘッダーを要求に配置しようとしています。これらはリクエストに属しておらず、何も役に立たない(自分に許可を与えることができる許可システムのポイントは何でしょうか)、応答にのみ表示される必要があります。
  • (通常、作成者がContent-Type: application/jsonAcceptを混同している場合)の内容を記述するリクエストボディを持たないGETリクエストにContent-Typeヘッダーを配置しようとしています。

これらのいずれの場合でも、プリフライトの必要性を回避するには、多くの場合、余分なリクエストヘッダーを削除するだけで十分です。


不透明な応答

HTTPリクエストを行う必要がある場合もありますが、レスポンスを読む必要はありません。例えば記録のためにログメッセージをサーバーに投稿する場合。

fetch APIXMLHttpRequestではなく)を使用している場合、CORSを使用しないように設定できます。

これでは、CORSに必要なことは何もできません。応答を読むことができなくなります。プリフライトが必要なリクエストを行うことはできません。

シンプルなリクエストを行うことができ、レスポンスが表示されず、開発者コンソールにエラーメッセージが表示されません。

その方法は、fetchを使用してリクエストを作成し、CORSでレスポンスを表示する権限を取得できない場合に表示されるChromeエラーメッセージで説明されています。

Origin '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プログラムの形式でデータを提示することで機能します。

Malloryが悪意のあるコードを提供しないようにボブを信頼する必要があります。

共通のテーマに注意してください。データを提供するサイトは、サードパーティのサイトがブラウザに送信しているデータにアクセスしてもよいことをブラウザに伝える必要があります。

JSONPは<script>要素を追加することで機能し、ページ内に既にある関数を呼び出すJavaScriptプログラムの形式でデータをロードするため、JSONを返すURLでJSONPテクニックを使用しようとすると失敗します。 JSONはJavaScriptではありません。

2つのリソースを単一のOriginに移動します

JSが実行されるHTMLドキュメントと要求されているURLが同じオリジン(同じスキーム、ホスト名、ポートを共有)にある場合、同じオリジンポリシーはデフォルトで許可を与えます。 CORSは必要ありません。

プロキシ

Mallorycouldは、サーバー側のコードを使用してデータを取得します(通常どおり、HTTPを介してサーバーからAliceのブラウザーに渡すことができます)。

次のいずれかです。

  • cORSヘッダーを追加する
  • 応答をJSONPに変換します
  • hTMLドキュメントと同じOriginに存在する

そのサーバー側のコードは、第三者(YQLなど)によってホストされる可能性があります。

Bobは、そのために許可を与える必要はありません。

これはマロリーとボブの間にあるので問題ありません。 BobがMalloryがAliceであると考え、MalloryにAliceとBobの間で機密にすべきデータを提供する方法はありません。

その結果、Malloryはこの手法を使用してpublicデータを読み取ることしかできません。

Webアプリ以外の何かを書く

「同じ起源ポリシーがWebページのJavaScriptにのみ適用される理由」セクションで述べたように、WebページにJavaScriptを記述しないことで、SOPを回避できます。

これは、JavaScriptとHTMLを使い続けることができないという意味ではありませんが、Node-WebKitやPhoneGapなどの他のメカニズムを使用して配布することができます。

ブラウザ拡張

同一拡張ポリシーが適用される前に、ブラウザー拡張機能が応答にCORSヘッダーを挿入することが可能です。

これらは開発には役立ちますが、本番サイトでは実用的ではありません(サイトのすべてのユーザーに、ブラウザーのセキュリティ機能を無効にするブラウザー拡張機能をインストールするよう要求するのは不合理です)。

また、単純なリクエストでのみ動作する傾向があります(プリフライトOPTIONSリクエストの処理時に失敗します)。

ローカル開発serverで適切な開発環境を用意することは、通常、より良いアプローチです。


その他のセキュリティリスク

SOP/CORSは XSSCSRF 、または SQLインジェクション の攻撃を緩和しないことに注意してください。独立して処理されます。


概要

  • 誰かelseサーバーへのCORSアクセスを可能にするyourクライアント側コードでできることは何もありません。
  • サーバーを制御する場合、リクエストは次のように行われます。CORSパーミッションを追加します。
  • あなたがそれを管理している人に親しんでいる場合:CORS権限を追加するように彼らに依頼してください。
  • パブリックサービスの場合:APIのドキュメントを読んで、クライアント側のJavaScriptを使用してアクセスすることについて彼らが言うことを確認してください。特定のURLを使用するかJSONPを使用するように指示される場合があります(またはまったくサポートされない場合があります)。
  • 上記のいずれにも当てはまらない場合:代わりにyourサーバーと通信するためにブラウザーを取得し、サーバーに他のサーバーからデータをフェッチさせて渡します。 (サードパーティがホストするサービスもあり、CORSヘッダーを公開されているアクセス可能なリソースに添付して使用できます)。
127
Quentin

ターゲットサーバーはクロスオリジンリクエストを許可する必要があります。エクスプレスで許可するには、httpオプションリクエストを処理するだけです:

app.options('/url...', function(req, res, next){
   res.header('Access-Control-Allow-Origin', "*");
   res.header('Access-Control-Allow-Methods', 'POST');
   res.header("Access-Control-Allow-Headers", "accept, content-type");
   res.header("Access-Control-Max-Age", "1728000");
   return res.sendStatus(200);
});
3
Daphoque

これは受け入れられた答えでは言及されていないので。

  • これはこの正確な質問には当てはまりませんが、その問題を検索する他の人を助けるかもしれません
  • これは、一部のケースでCORSエラーを防ぐためにクライアントコードで実行できることです。

Simple Requests を使用できます。
「単純なリクエスト」を実行するには、リクエストがいくつかの条件を満たす必要があります。例えば。 POSTGETHEADメソッドのみを許可し、一部の特定のヘッダーのみを許可します(すべての条件を見つけることができます here )。

クライアントコードが、リクエストに修正値を含む影響を受けるヘッダー(例: "Accept")を明示的に設定しない場合、一部のクライアントがこれらを設定することがありますmightいくつかの「非標準」値を持つヘッダーが自動的に送信されると、サーバーはそれを単純な要求として受け入れなくなります。これにより、CORSエラーが発生します。

2
zwif

これは、CORSエラーが原因で発生しています。 CORSはCross Origin Resource Sharingの略です。簡単に言えば、このエラーは、別のドメインからドメイン/リソースにアクセスしようとすると発生します。

詳細については、こちらをご覧ください: CORS error with jquery

これを修正するには、他のドメインにアクセスできる場合、サーバーでAccess-Control-Allow-Originを許可する必要があります。これはヘッダーに追加できます。すべてのリクエスト/ドメインまたは特定のドメインに対してこれを有効にできます。

クロスオリジンリソース共有(CORS)ポストリクエストを機能させる方法

これらのリンクは役立つかもしれません

2
Vishnu

このCORSの問題は、(他の理由で)さらに詳しくは説明されていません。

現在、この問題はさまざまな理由で発生しています。フロントエンドも 'Access-Control-Allow-Origin'ヘッダーエラーを返しています。

間違ったURLを指したため、このヘッダーが適切に反映されませんでした(その中で推測しました)。 localhost(フロントエンド)->セキュリティで保護されていないhttp(httpsを想定)への呼び出し、フロントエンドからのAPIエンドポイントが正しいプロトコルを指していることを確認します。

0
morph85