INTEGRITY Dokumentace

CORS

Sdílení zdrojů mezi zdroji (CORS) je mechanismus, který pomocí HTTP hlaviček uděluje webové aplikaci běžící na jednom originu oprávnění přistupovat k vybraným zdrojům na jiném originu. Webová aplikace provede cross-origin HTTP požadavek ve chvíli, kdy si vyžádá zdroj s jiným originem, než má sama, ať už jde o doménu, protokol nebo port.

Aby požadavek CORS mohl dosáhnout webu chráněného službou Access, musí obsahovat platný CF-Authorization cookie. To může v závislosti na typu požadavku vyžadovat další konfiguraci:

Povolit jednoduché požadavky

Pokud odešlete jednoduchý požadavek CORS na doménu chráněnou pomocí Access a ještě nejste přihlášeni, požadavek vrátí CORS error. Tuto chybu můžete vyřešit dvěma způsoby:

Ruční ověření

  1. Navštivte cílovou doménu ve svém prohlížeči. Zobrazí se přihlašovací stránka Access.
  2. Přihlaste se do cílové domény. Tím se vygeneruje CF-Authorization cookie.
  3. Obnovte stránku, která odeslala požadavek CORS. Obnovení znovu odešle požadavek s nově vygenerovaným cookie.

Povolit preflight požadavky

Pokud odešlete preflight cross-origin požadavek na doménu chráněnou pomocí Access, požadavek OPTIONS vrátí 403 chybu. Tato chyba nastává bez ohledu na to, zda jste do domény přihlášeni. Je to proto, že prohlížeč záměrně nikdy neposílá cookies s požadavky OPTIONS. Cloudflare proto preflight požadavek zablokuje, což způsobí selhání výměny CORS.

Tuto chybu můžete vyřešit třemi způsoby:

Obejít požadavky OPTIONS na origin

Cloudflare můžete nakonfigurovat tak, aby posílal požadavky OPTIONS přímo na váš origin server. Chcete-li pro požadavky OPTIONS obejít Access:

  1. V Cloudflare dashboard, přejděte na Zero Trust > Řízení přístupu > Aplikace.
  2. Najděte origin, který bude přijímat požadavky OPTIONS, a vyberte Konfigurovat.
  3. Přejděte na Pokročilá nastavení > Nastavení sdílení zdrojů mezi zdroji (CORS).
  4. Zapněte Obejít požadavky options na origin. Tím se odeberou veškerá stávající nastavení CORS pro tuto aplikaci.

I tak je důležité vynucovat CORS pro Access JWT: tuto možnost byste měli použít pouze v případě, že máte vynucování CORS nastaveno i na svém origin serveru.

Nakonfigurujte odpověď na preflight požadavky

Cloudflare můžete nakonfigurovat tak, aby na požadavek OPTIONS odpovídal místo vás. Požadavek OPTIONS se k vašemu origin serveru nikdy nedostane. Jakmile se preflight výměna vyřeší, prohlížeč následně odešle hlavní požadavek, který již obsahuje ověřovací cookie (za předpokladu, že jste se do domény chráněné Access přihlásili).

Chcete-li nakonfigurovat, jak Cloudflare reaguje na požadavky typu preflight:

  1. V Cloudflare dashboard, přejděte na Zero Trust > Řízení přístupu > Aplikace.

  2. Najděte origin, který bude přijímat požadavky OPTIONS, a vyberte Konfigurovat.

  3. Přejděte na Pokročilá nastavení > Nastavení sdílení zdrojů mezi zdroji (CORS).

  4. Nakonfigurujte tyto Nastavení CORS tak, aby odpovídalo hlavičkám odpovědi odesílaným vaším origin serverem.

    Pokud jste například nakonfigurovali api.mysite.coma vrátit následující hlavičky:

    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',
    }

    poté přejděte na api.mysite.com v Access a nakonfigurovat Access-Control-Allow-Origin, Access-Control-Allow-Credentials, Access-Control-Allow-Methods, a Access-Control-Allow-Headers. Příklad konfigurace nastavení CORS v Cloudflare One

  5. Vyberte Save.

  6. (Volitelné) Konfiguraci můžete zkontrolovat odesláním požadavku OPTIONS na origin s curl. Například,

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

    výstupem by měla být odpověď podobná této:

    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

Odesílání ověřovacího tokenu pomocí Cloudflare Worker

Pokud máte dvě pobočky chráněné pomocí Cloudflare Access, example.com a api.mysite.com, požadavky mezi těmito dvěma budou podléhat kontrolám CORS. Uživatelé, kteří se přihlásí do example.com obdrží soubor cookie pro example.com. Když si prohlížeč uživatele vyžádá api.mysite.com, Cloudflare Access hledá cookie specifické pro api.mysite.com. Požadavek selže, pokud se uživatel ještě nepřihlásil do api.mysite.com.

Chcete-li se vyhnout dvojímu přihlašování, můžete vytvořit Cloudflare Worker, který automaticky odesílá přihlašovací údaje na api.mysite.com.

Předpoklady

1. Vygenerujte service token

Postupujte podle tyto pokyny a vygenerovat nový service token Access. Zkopírujte Client ID a Client Secret na bezpečné místo, protože je budete potřebovat v pozdějším kroku.

2. Přidejte zásadu Service Auth

  1. V Cloudflare dashboard, přejděte na Zero Trust > Řízení přístupu > Aplikace.

  2. Najděte svůj api.mysite.com aplikaci a vyberte Konfigurovat.

  3. Vyberte Zásady kartě.

  4. Přidejte následující zásadu:

    Akce Typ pravidla Selektor
    Service Auth Include Service Token

3. Vytvořte nový Worker

Otevřete terminál a spusťte následující příkaz:

npm create cloudflare@latest -- authentication-worker

Tímto budete vyzváni k instalaci create-cloudflare balíček a provede vás nastavením.

Při nastavení vyberte následující možnosti:

Přejděte do adresáře projektu.

cd authentication-worker

Otevřete /src/index.js a odstraňte stávající kód a vložte následující příklad:

// 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,
			});
		}
	},
};

Poté nasaďte Worker do svého účtu Cloudflare:

npx wrangler deploy

4. Nakonfigurujte Worker

  1. V Cloudflare dashboard, přejděte do Workers & Pages stránce.

    Přejděte na Workers & Pages ↗
  2. Vyberte nově vytvořeného Workera.

  3. V Triggery kartě přejděte na Trasy a přidejte example.com/api/*. Worker je umístěn na podcestě example.com a zabraňte mezizdrojovému (cross-origin) požadavku.

  4. V Nastavení kartě vyberte Proměnné.

  5. V části Proměnné prostředí, přidejte následující tajné proměnné:

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

Client ID a Client Secret se kopírují z vašeho token služby.

  1. Povolte Šifrovat možnost pro každou proměnnou a vyberte Save.

5. Aktualizujte adresy URL požadavků HTTP

Upravte svůj example.com aplikaci, aby odesílala všechny požadavky na example.com/api/ místo api.mysite.com.

Požadavky HTTP by nyní měly bez problémů fungovat mezi dvěma různými doménami chráněnými Access. Když se uživatel přihlásí do example.com, prohlížeč odešle požadavek na Worker místo na api.mysite.com. Worker přidá token služby Access do hlaviček požadavku a poté požadavek přesměruje na api.mysite.com. Protože token služby odpovídá zásadě Service Auth, uživatel se už nemusí přihlašovat k api.mysite.com.

Řešení potíží

Obecně doporučujeme při řešení problémů s CORS následující kroky:

  1. Zachyťte soubor HAR s popisem problému a zároveň zaznamenejte výstup konzole JS. Samotný soubor HAR totiž neposkytne úplný přehled o příčině problémů s cross-origin.
  2. Ujistěte se, že aplikace nastavila credentials: 'same-origin' ve všech požadavcích fetch nebo XHR.
  3. Pokud používáte nastavení cross-origin u tagů script musí být nastaveny na hodnotu "use-credentials".