1. ホーム
  2. ジャバスクリプト

[解決済み] XMLHttpRequestが読み込めない XXX 'Access-Control-Allow-Origin' ヘッダがない

2022-03-04 16:04:08

質問

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

私は、express.jsサーバーのインスタンスを起動するGruntプロセスを持っています。これは、ついさっきまで全く問題なく動作していましたが、Chrome(最新版)の開発者コンソールのエラーログに次のように表示され、空白のページを提供するようになりました。

<ブロッククオート

XMLHttpRequestを読み込むことができません https://www.example.com/ 要求されたファイルに 'Access-Control-Allow-Origin' ヘッダーが存在しない。 リソースを使用します。オリジン ' http://localhost:4300 ' はアクセスを許可されません。

何が原因でページにアクセスできないのですか?

どうすればいいですか?

tl;dr - 最後に要約があり、答えの中に見出しがあるので、関連する部分を簡単に見つけることができます。を理解するための有用な背景を提供するため、すべてを読むことをお勧めします。 なぜ を見ることができるようになります。 どのように は、さまざまな状況に対応しやすくなっています。

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

これは 同一生成元ポリシー . これは、ブラウザが実装しているセキュリティ機能です。

この例は、XMLHttpRequest に対してどのように実装されているかを示していますが (fetch を使用しても同じ結果が得られます)、他のものにも適用できます (たとえば、画像を <canvas> に読み込まれるドキュメント、あるいは <iframe> ) の実装が若干異なるだけです。

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

SOPの必要性を示す標準的なシナリオは、次のように示される。 三文字 :

  • アリスはウェブブラウザを持つ人間である
  • ボブはウェブサイトを運営している( https://www.[website].com/ の例では)
  • Malloryはウェブサイトを運営しています( http://localhost:4300 の例では)

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

アリスはマロリーのウェブサイトにアクセスします。そのウェブサイトには、アリスのブラウザがボブのウェブサイトにHTTPリクエストをするためのJavaScriptがあります(アリスのIPアドレスから、彼女のクッキーなどを使って)。これは次のような簡単なものです。 XMLHttpRequest を読み込んで responseText .

ブラウザの同一生成元ポリシーにより、そのJavaScriptはボブのウェブサイトから返されたデータ(ボブとアリスはマロリーにはアクセスして欲しくない)を読み取ることができません。(例えば、画像を表示するために <img> 画像のコンテンツは JavaScript(または Mallory)には公開されないからです。 意志 同一起源違反のエラーが発生します)。


同一生成元ポリシーが適用されないと思われる理由

任意のURLについて、SOPが不要である可能性があります。このようなケースでよくあるシナリオをいくつか紹介します。

  • アリス、ボブ、マロリーは同一人物である。
  • ボブは完全に公開された情報を提供している

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


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

ブラウザの拡張機能 * や、ブラウザの開発ツールの「ネットワーク」タブ、Postmanのようなアプリケーションは、インストールされたソフトウェアです。これらは、あるウェブサイトから別のウェブサイトに属するJavaScriptにデータを渡しているわけではありません。 その別のウェブサイトを訪問したからといって . ソフトウェアのインストールは、通常、より意識的な選択が必要です。

リスクと思われる第三者(マロリー)がいない。

* ブラウザの拡張機能は、クロスオリジンの問題を避けるために、慎重に記述する必要があります。 例として、Chromeのドキュメントをご覧ください .


JSでデータを読み込まずにページ内に表示できる理由

マロリーのサイトでは、ブラウザが第三者からデータを取得して表示させることができる状況がいくつかあります(例えば、ブラウザに <img> 要素で画像を表示させることができます)。しかし、マロリーのJavaScriptがそのリソースのデータを読むことは不可能で、アリスのブラウザとボブのサーバーだけがそれを行うことができるので、まだ安全です。


CORS

Access-Control-Allow-Origin HTTP レスポンス ヘッダは、エラーメッセージで参照されている CORS この規格は、ボブがマロリーのサイトに対して、アリスのブラウザ経由でデータにアクセスする許可を明示的に与えることを可能にします。

基本的な実装は、以下を含むだけです。

Access-Control-Allow-Origin: *

... どのウェブサイトでもデータを読めるように、レスポンスヘッダに記述します。

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

...は、特定のサイトからのアクセスのみを許可するもので、Bobはそれを Origin リクエスト ヘッダを使用して、すべてのサイトではなく、複数のサイトからのアクセスを許可します。

ボブがその応答ヘッダをどのように設定するかの詳細は、ボブのHTTPサーバおよび/またはサーバ側のプログラミング言語によって異なります。そこには 様々な一般的な設定のためのガイドのコレクション が参考になるかもしれません。

注:リクエストによっては複雑なため プリフライト ブラウザがJSが行いたいGET/POST/PUT/その他のリクエストを送信する前に、サーバーが応答しなければならないOPTIONSリクエストです。を追加するだけのCORSの実装は Access-Control-Allow-Origin を特定のURLに追加すると、しばしばこの問題でつまづくことがあります。


明らかにCORS経由で許可を与えることは、ボブがどちらかの場合にのみ行うことです。

  • データが非公開であること または
  • マロリーは信頼されていた

これらのヘッダーはどのように追加するのですか?

サーバーサイドの環境に依存します。

可能であれば、CORS を処理するために設計されたライブラリを使用すると、すべてを手動で処理する必要がなく、簡単なオプションを提示します。

Enable-Cors.org には、特定のプラットフォームやフレームワークのためのドキュメントのリストがあり、役に立つかもしれません。

でも、私はボブじゃないんです!

の標準的な仕組みはありません。 マロリー はこのヘッダを追加するために、彼女が管理していないボブのウェブサイトから来る必要があるからです。

Bob が公開 API を実行している場合、CORS を有効にするメカニズムがあるかもしれません(おそらく、特定の方法でリクエストをフォーマットするか、Bob のサイトの開発者ポータルサイトにログインした後の設定オプションによって)。しかし、これは Bob によって実装されるメカニズムでなければならない。MalloryはBobのサイトのドキュメントを読んで、何かが利用可能かどうかを確認することができますし、Bobと話をしてCORSを実装するように依頼することもできます。


エラーメッセージに "Response for preflight" と記載されている。

一部のクロスオリジンリクエストは プリフライト .

これは、(大雑把に言うと)クロスオリジンリクエストを行おうとしたときに起こります。

  • Cookieなどのクレデンシャルを含む
  • 通常の HTML フォームでは生成できない (たとえば、カスタムヘッダや Content-Type があり、フォームの enctype ).

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

このような場合は この回答の残りの部分はそのまま適用されます。 が、サーバーがプリフライトリクエストをリッスンできることも確認する必要があります (このリクエストは OPTIONS (そして GET , POST またはあなたが送ろうとしていたもの)を送信し、それに対して正しい Access-Control-Allow-Origin ヘッダーのみならず Access-Control-Allow-MethodsAccess-Control-Allow-Headers を使用して、特定のHTTPメソッドやヘッダを許可することができます。

間違ってプリフライトをトリガーしてしまった場合

Ajax リクエストを作成する際に間違いを犯すことがあり、それがきっかけでプリフライトが必要になることがあります。API がクロスオリジンリクエストを許可するように設計されていて、プリフライトが必要なものを要求していない場合、これはアクセスを中断させる可能性があります。

このきっかけとなるよくあるミスは以下の通りです。

  • を配置しようとすると Access-Control-Allow-Origin といったCORSレスポンスヘッダをリクエストに付加します。これらはリクエストには属さず、何の役にも立ちません (自分に権限を与えることができる権限システムにはどんな意味があるのでしょうか?)。また、レスポンスにのみ表示されなければなりません。
  • を付けようとすると Content-Type: application/json ヘッダーの内容を説明するリクエストボディを持たない GET リクエストに適用されます (典型的な例として、作者が Content-TypeAccept ).

これらのいずれの場合でも、余分なリクエストヘッダを削除すれば、プリフライトの必要性を回避できることが多いでしょう(シンプルなリクエストをサポートするがプリフライトされないAPIと通信する場合の問題は解決されます)。


不透明なレスポンス

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

を使用している場合 その fetch API (むしろ XMLHttpRequest を使用しないように設定することができます。

この場合、CORSに要求されることは何もできないことに注意してください。レスポンスを読むことができなくなります。プリフライトを必要とするリクエストを行うことができなくなります。

単純なリクエストを行い、レスポンスを見ず、Developer Console をエラーメッセージで埋め尽くさないようにすることができます。

この方法を説明するために、Chromeのエラーメッセージは fetch で、CORSでレスポンスの閲覧権限が得られない。

<ブロッククオート

でのフェッチへのアクセスは、' https://example.com/ ' から、オリジン ' https://example.net ' は、CORS ポリシーによってブロックされました。いいえ ' Access-Control-Allow-Origin ヘッダがリクエストされたリソースに存在します。不透明な応答が必要な場合は、要求のモードを「no-cors」に設定し、CORSを無効にしてリソースを取得します。

このように

fetch("http://example.com", { mode: "no-cors" });


CORSの代替となるもの

JSONP

Bob は、次のようなハックを使ってデータを提供することもできます。 JSONP これは、CORSが登場する前に人々がクロスオリジンAjaxを行った方法である。

これは、データをJavaScriptのプログラムの形で提示し、Malloryのページにデータを注入することで機能します。

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

共通するテーマに注目してください。データを提供するサイトは、第三者のサイトがブラウザに送信するデータにアクセスしても問題ないことをブラウザに伝えなければなりません。

JSONPは、JSONPの文字列に <script> JSONはJavaScriptではないため、JSONを返すURLでJSONPの手法を使用しようとすると、通常はCORBエラーで失敗します。

2つのリソースを1つのOriginに移動させる

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

プロキシ

マロリー かもしれない は、サーバサイドのコードを使ってデータを取得します (その後、通常通り HTTP でサーバからアリスのブラウザにデータを渡すことができます)。

のどちらかになります。

  • CORSヘッダを追加する
  • レスポンスをJSONPに変換する
  • HTMLドキュメントと同じオリジンに存在する

サーバーサイドのコードは、サードパーティ(CORS Anywhereなど)によってホストされる&ampに書かれる可能性があります。この場合、プライバシーへの影響に注意してください。サードパーティは、誰が何をプロキシしているかを監視することができます。

ボブはそのためにパーミッションを与える必要はない。

これはMalloryとBobの間だけのことなので、セキュリティ上の意味はありません。ボブはマロリーをアリスだと思い、アリスとボブの間で秘密にしておくべきデータをマロリーに提供することはできません。

その結果、Malloryはこのテクニックを使って、以下のものを読み取ることができます。 公開 のデータです。

ただし、他人のウェブサイトからコンテンツを取得し、自分のウェブサイトに表示することは、以下の違反になる可能性があります。 著作権 法的措置の対象となります。

Webアプリ以外の書き方

セクション「"Same Origin PolicyがWebページ内のJavaScriptにのみ適用される理由"」で述べたように、Webページ内にJavaScriptを書かないことで、SOPを回避することができます。

だからといって、JavaScriptとHTMLを使い続けることはできませんが、Node-WebKitやPhoneGapなど、何か別の仕組みを使って配布することは可能です。

ブラウザの拡張機能

同一生成元ポリシーが適用される前に、ブラウザ拡張機能がレスポンスにCORSヘッダを注入することは可能です。

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

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

ローカル開発で適切な開発環境を持つ サーバー は、通常、より良いアプローチです。


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

SOP/CORSでは軽減されないことにご注意ください。 XSS , CSRF または SQLインジェクション の攻撃には、個別に対応する必要があります。


概要

  • でできることは何もありません。 あなたの クライアント側のコードでCORSアクセスを可能にする 他の人の サーバに接続します。
  • リクエストが行われるサーバーを制御する場合。CORSパーミッションを追加します。
  • 管理している人と仲が良い場合。その人にCORSパーミッションを追加してもらう。
  • 公共サービスである場合
    • APIドキュメントを読んで、クライアントサイドのJavaScriptでアクセスする際の注意事項を確認してください。
      • 特定のURLを使用するように指示されることがあります
      • JSONPをサポートしている場合がある
      • クライアントサイドのコードからのクロスオリジンアクセスを全くサポートしていないかもしれない(これはセキュリティ上の理由から意図的に決めたことかもしれない、特にリクエストごとに個人用のAPI Keyを渡さなければならない場合)。
    • 必要のないプリフライトリクエストをトリガーしていないことを確認する。API は単純なリクエストには権限を与えるかもしれませんが、プリフライトされたリクエストには権限を与えないかもしれません。
  • 上記のいずれにも当てはまらない場合 ブラウザから あなたの のサーバーの代わりに、あなたのサーバーに他のサーバーからデータを取得させ、それを渡すようにします。(一般にアクセス可能なリソースにCORSヘッダーを付加するサードパーティ製のホストサービスもあり、これを利用することもできます)。