INTEGRITY Документация

CORS

Совместное использование ресурсов между разными источниками (CORS) представляет собой механизм, который с помощью заголовков HTTP предоставляет веб-приложению, работающему на одном источнике (origin), разрешение на обращение к отдельным ресурсам на другом источнике. Веб-приложение выполняет межисточниковый HTTP-запрос (cross-origin), когда запрашивает ресурс, источник которого (домен, протокол или порт) отличается от его собственного.

Чтобы CORS-запрос дошёл до сайта, защищённого Access, он должен содержать действительный CF-Authorization cookie. В зависимости от типа запроса это может потребовать дополнительной настройки:

Разрешить простые запросы

Если вы выполните простой запрос CORS к домену, защищённому Access, не выполнив предварительный вход, запрос вернёт CORS error. Устранить эту ошибку можно двумя способами:

Ручная аутентификация

  1. Откройте целевой домен в браузере. Откроется страница входа Access.
  2. Войдите в целевой домен. Это создаёт CF-Authorization cookie.
  3. Обновите страницу, которая отправила CORS-запрос. При обновлении запрос отправляется повторно с новым сгенерированным файлом cookie.

Разрешить preflight-запросы

Если вы выполните предварительный (preflight) кросс-доменный запрос к домену, защищённому Access, запрос OPTIONS вернёт 403 ошибка. Эта ошибка возникает независимо от того, выполнен ли вход в домен, поскольку браузер изначально не отправляет файлы cookie с запросами OPTIONS. Поэтому Cloudflare блокирует preflight-запрос, из-за чего обмен CORS завершается сбоем.

Устранить эту ошибку можно тремя способами:

Bypass OPTIONS requests to origin

Вы можете настроить Cloudflare так, чтобы он отправлял запросы OPTIONS напрямую на ваш исходный сервер. Чтобы обойти Access для запросов OPTIONS:

  1. В Панель управления Cloudflare, перейдите в Zero Trust > Контроль доступа > Приложения.
  2. Найдите источник, который будет получать запросы OPTIONS, и выберите Настройте.
  3. Перейдите в Расширенные настройки > Настройки совместного использования ресурсов между разными источниками (CORS).
  4. Включите Не проверять запросы OPTIONS к источнику. Это удалит все существующие настройки CORS для этого приложения.

По-прежнему важно обеспечивать соблюдение CORS для Access JWT: этот параметр следует использовать только в том случае, если применение CORS уже настроено на вашем исходном сервере.

Настройте ответ на предварительные запросы

Вы можете настроить Cloudflare так, чтобы он отвечал на запрос OPTIONS от вашего имени. Запрос OPTIONS никогда не доходит до вашего исходного сервера. После завершения предварительного обмена (preflight) браузер отправит основной запрос, который уже включает cookie аутентификации (при условии, что вы вошли в домен, защищённый Access).

Чтобы настроить, как Cloudflare обрабатывает предварительные запросы (preflight):

  1. В Панель управления Cloudflare, перейдите в Zero Trust > Контроль доступа > Приложения.

  2. Найдите источник, который будет получать запросы OPTIONS, и выберите Настройте.

  3. Перейдите в Расширенные настройки > Настройки совместного использования ресурсов между разными источниками (CORS).

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

    затем перейдите в api.mysite.com в Access и настройте Access-Control-Allow-Origin, Access-Control-Allow-Credentials, Access-Control-Allow-Methods, а также Access-Control-Allow-Headers. Пример настройки CORS в Cloudflare One

  5. Выберите Save.

  6. (Необязательно) Вы можете проверить конфигурацию, отправив запрос OPTIONS на источник с curl. Например,

    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, example.com и api.mysite.com, запросы между ними будут проходить проверки CORS. Пользователи, которые входят в example.com будет выдан файл cookie для example.com. Когда браузер пользователя запрашивает api.mysite.com, Cloudflare Access ищет файл cookie, специфичный для api.mysite.com. Запрос завершится сбоем, если пользователь ещё не выполнил вход в api.mysite.com.

Чтобы не входить в систему дважды, можно создать Cloudflare Worker, который автоматически отправляет учётные данные для аутентификации в api.mysite.com.

Предварительные требования

1. Создайте токен службы

Следуйте эти инструкции чтобы создать новый токен службы Access. Скопируйте Client ID и Client Secret в безопасное место, так как они понадобятся вам на одном из следующих шагов.

2. Добавьте политику Service Auth

  1. В Панель управления Cloudflare, перейдите в Zero Trust > Контроль доступа > Приложения.

  2. Найдите свой api.mysite.com приложение и выберите Настройте.

  3. Выберите Политики на вкладке.

  4. Добавьте следующую политику:

    Действие Тип правила Селектор
    Service Auth Включить Service Token

3. Создайте новый Worker

Откройте терминал и выполните следующую команду:

npm create cloudflare@latest -- authentication-worker

Это предложит вам установить create-cloudflare пакет и проведёт вас через процесс установки.

Для настройки выберите следующие параметры:

Перейдите в каталог проекта.

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. В Триггеры вкладке перейдите в Маршруты и добавьте example.com/api/*. Worker размещается на подпути example.com чтобы избежать кросс-доменного запроса.

  4. В Настройки вкладке выберите Переменные.

  5. В разделе Переменные окружения, добавьте следующее секретные переменные:

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

Client ID и Client Secret копируются из вашего токен службы.

  1. Включить Зашифровать для каждой переменной и выберите Save.

5. Обновите URL-адреса HTTP-запросов

Измените ваш example.com приложение отправлять все запросы на example.com/api/ вместо api.mysite.com.

Теперь HTTP-запросы должны корректно работать между двумя разными доменами, защищенными Access. Когда пользователь выполняет вход в example.com, браузер отправляет запрос к Worker вместо запроса к api.mysite.com. Worker добавляет токен службы Access в заголовки запроса, а затем перенаправляет запрос на api.mysite.com. Поскольку токен службы соответствует политике Service Auth, пользователю больше не нужно входить в api.mysite.com.

Устранение неполадок

Как правило, при устранении проблем с CORS мы рекомендуем выполнить следующие действия:

  1. Соберите файл HAR с описанием проблемы, а также одновременно записанный вывод консоли JS. Это связано с тем, что сам по себе файл HAR не даёт полного понимания причины проблем с cross-origin.
  2. Убедитесь, что приложение задало credentials: 'same-origin' во всех запросах fetch или XHR.
  3. Если вы используете настройка cross-origin на тегах script, для них нужно установить значение "use-credentials".