Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

CORS

最終更新 Markdown で表示Agent セットアップ

クロスオリジンリソース共有(CORS)は、HTTP ヘッダーを使い、あるオリジンで動く Web アプリケーションが、別オリジンの指定したリソースにアクセスできるようにする仕組みです。ドメイン、プロトコル、ポートのいずれかが異なるリソースを要求すると、クロスオリジン HTTP リクエストになります。

Access で保護されたサイトに CORS リクエストが届くには、有効な CF-Authorization Cookie が必要です。リクエストの種類によって、追加の設定が必要になることがあります。

シンプルリクエストを許可する

Access で保護されたドメインへシンプルな CORS リクエストを送り、まだログインしていない場合、CORS error が返ります。次の 2 つの方法で解消できます。

手動で認証する

  1. ブラウザーで対象ドメインを開きます。Access のログインページが表示されます。
  2. 対象ドメインにログインします。CF-Authorization Cookie が発行されます。
  3. CORS リクエストを出したページを更新します。新しい Cookie 付きでリクエストが再送されます。

プリフライト付きリクエストを許可する

Access で保護されたドメインへプリフライト付きクロスオリジンリクエストを送ると、OPTIONS リクエストは 403 エラーを返します。ドメインにログイン済みでも同じです。ブラウザーは設計上、OPTIONS リクエストに Cookie を付けません。そのため Cloudflare がプリフライトリクエストをブロックし、CORS 交換が失敗します。

次の 3 つの方法で解消できます。

OPTIONS リクエストをオリジンへバイパスする

Cloudflare が OPTIONS リクエストをオリジンサーバーへ直接送るように設定できます。Access を OPTIONS リクエストでバイパスするには、次の手順を行います。

  1. Cloudflare ダッシュボードZero Trust > Access controls > Applications を開きます。
  2. OPTIONS リクエストを受け取るオリジンを探し、Configure を選択します。
  3. Advanced settings > Cross-Origin Resource Sharing (CORS) settings を開きます。
  4. Bypass options requests to origin をオンにします。このアプリケーションの既存の CORS 設定はすべて削除されます。

Access JWT に対する CORS の適用は、引き続き重要です。このオプションは、オリジンサーバー側で CORS を適用している場合にだけ使ってください。

プリフライトリクエストへの応答を設定する

Cloudflare が代わりに OPTIONS リクエストへ応答するように設定できます。OPTIONS リクエストはオリジンに届きません。プリフライト交換が終わると、ブラウザーは本リクエストを送ります。こちらには認証 Cookie が付きます(Access で保護されたドメインにログイン済みの場合)。

プリフライトリクエストへの Cloudflare の応答を設定するには、次の手順を行います。

  1. Cloudflare ダッシュボードZero Trust > Access controls > Applications を開きます。

  2. OPTIONS リクエストを受け取るオリジンを探し、Configure を選択します。

  3. Advanced settings > Cross-Origin Resource Sharing (CORS) settings を開きます。

  4. オリジンが返すレスポンスヘッダーに合わせて、これらの CORS 設定 を合わせます。

    たとえば、api.mysite.com が次のヘッダーを返す場合:

    headers: {
      'Access-Control-Allow-Origin': 'https://example.com',
      'Access-Control-Allow-Credentials' : true,
      'Access-Control-Allow-Methods': 'GET, OPTIONS',
      'Access-Control-Allow-Headers': 'office',
      'Content-Type': 'application/json',
    }

    Access で api.mysite.com を開き、Access-Control-Allow-OriginAccess-Control-Allow-CredentialsAccess-Control-Allow-MethodsAccess-Control-Allow-Headers を設定します。 Cloudflare One の CORS 設定例

  5. Save を選択します。

  6. (任意)curl でオリジンへ OPTIONS リクエストを送り、設定を確認できます。例:

    curl --head --request OPTIONS https://api.mysite.com \
    --header 'origin: https://example.com' \
    --header 'access-control-request-method: GET'

    次のような応答が返ります。

    HTTP/2 200
    date: Tue, 24 May 2022 21:51:21 GMT
    vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
    access-control-allow-origin: https://example.com
    access-control-allow-methods: GET
    access-control-allow-credentials: true
    expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
    report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=A%2FbOOWJio%2B%2FjuJv5NC%2FE3%2Bo1zBl2UdjzJssw8gJLC4lE1lzIUPQKqJoLRTaVtFd21JK1d4g%2BnlEGNpx0mGtsR6jerNfr2H5mlQdO6u2RdOaJ6n%2F%2BS%2BF9%2Fa12UromVLcHsSA5Y%2Fj72tM%3D"}],"group":"cf-nel","max_age":604800}
    nel: {"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}
    server: cloudflare
    cf-ray: 7109408e6b84efe4-EWR

Cloudflare Worker で認証トークンを送る

Cloudflare Access で保護された 2 つのサイト(example.comapi.mysite.com)がある場合、両者の間のリクエストは CORS チェックの対象です。example.com にログインしたユーザーには、example.com 用の Cookie が発行されます。ブラウザーが api.mysite.com を要求すると、Cloudflare Access は api.mysite.com 専用の Cookie を探します。ユーザーがまだ api.mysite.com にログインしていなければ、リクエストは失敗します。

2 回ログインしなくて済むように、api.mysite.com へ認証情報を自動送信する Cloudflare Worker を作成できます。

前提条件

1. サービストークンを生成する

こちらの手順 で、新しい Access サービストークンを生成します。後の手順で使うので、Client IDClient Secret を安全な場所にコピーします。

2. Service Auth ポリシーを追加する

  1. Cloudflare ダッシュボードZero Trust > Access controls > Applications を開きます。

  2. api.mysite.com アプリケーションを探し、Configure を選択します。

  3. Policies タブを選択します。

  4. 次のポリシーを追加します。

    Action Rule type Selector
    Service Auth Include Service Token

3. 新しい Worker を作成する

ターミナルを開き、次のコマンドを実行します。

npm create cloudflare@latest -- authentication-worker

create-cloudflare パッケージのインストールを求められ、セットアップが進みます。

セットアップでは、次のオプションを選びます。

  • What would you like to start with? では、Hello World example を選びます。
  • Which template would you like to use? では、Worker only を選びます。
  • Which language do you want to use? では、JavaScript を選びます。
  • Do you want to use git for version control? では、Yes を選びます。
  • Do you want to deploy your application? では、No を選びます(デプロイ前にいくつか変更します)。

プロジェクトディレクトリに移動します。

cd authentication-worker

/src/index.js を開き、既存のコードを削除して、次の例を貼り付けます。

// The hostname where your API lives
const originalAPIHostname = "api.mysite.com";

export default {
	async fetch(request, env) {
		// Change just the host. If the request comes in on example.com/api/name, the new URL is api.mysite.com/api/name
		const url = new URL(request.url);
		url.hostname = originalAPIHostname;

		// If your API is located on api.mysite.com/anyname (without "api/" in the path),
		// remove the "api/" part of example.com/api/name

		// url.pathname = url.pathname.substring(4)

		// Best practice is to always use the original request to construct the new request
		// to clone all the attributes. Applying the URL also requires a constructor
		// since once a Request has been constructed, its URL is immutable.
		const newRequest = new Request(url.toString(), request);

		newRequest.headers.set("cf-access-client-id", env.CF_ACCESS_CLIENT_ID);
		newRequest.headers.set("cf-access-client-secret", env.CF_ACCESS_CLIENT_SECRET);
		try {
			const response = await fetch(newRequest);

			// Copy over the response
			const modifiedResponse = new Response(response.body, response);

			// Delete the set-cookie from the response so it doesn't override existing cookies
			modifiedResponse.headers.delete("set-cookie");

			return modifiedResponse;
		} catch (e) {
			return new Response(JSON.stringify({ error: e.message }), {
				status: 500,
			});
		}
	},
};

次に、Worker を Cloudflare アカウントへデプロイします。

npx wrangler deploy

4. Worker を設定する

  1. Cloudflare ダッシュボードWorkers & Pages ページを開きます。

    Workers & Pages を開く ↗
  2. 作成した Worker を選択します。

  3. Triggers タブの Routesexample.com/api/* を追加します。クロスオリジンリクエストを避けるため、Worker は example.com のサブパスに置きます。

  4. Settings タブで Variables を選択します。

  5. Environment Variables に、次の シークレット変数 を追加します。

    • CF_ACCESS_CLIENT_ID = <service token Client ID>
    • CF_ACCESS_CLIENT_SECRET = <service token Client Secret>

Client ID と Client Secret は、サービストークン からコピーします。

  1. 各変数で Encrypt を有効にし、Save を選択します。

5. HTTP リクエスト URL を更新する

example.com アプリケーションを変更し、api.mysite.com ではなく example.com/api/ へすべてのリクエストを送るようにします。

これで、Access で保護された 2 つのドメイン間でも HTTP リクエストが切れずに動きます。ユーザーが example.com にログインすると、ブラウザーは api.mysite.com ではなく Worker にリクエストします。Worker は Access サービストークンをリクエストヘッダーに付け、api.mysite.com へ転送します。サービストークンが Service Auth ポリシーに一致するため、ユーザーは api.mysite.com にログインする必要がありません。

トラブルシューティング

CORS の問題を調べるときは、一般に次の手順を推奨します。

  1. 問題が再現している HAR ファイルと、同時に記録した JS コンソールログを取得します。HAR ファイルだけでは、クロスオリジン問題の原因が十分に分かりません。
  2. アプリケーションの fetch または XHR リクエストすべてで、credentials: 'same-origin' が設定されていることを確認します。
  3. script タグで crossorigin 属性 を使っている場合は、"use-credentials" に設定します。

役に立ちましたか?