CORS просто

Прежде чем описывать CORS, стоит упомянуть об ограничениях браузеров:

  • запросы с https на http не разрешаются
  • запросы с http на https разрешаются
  • запросы с http на http разрешаются, поэтому в разработке лучше использовать http, чтобы не вводить thisisunsafe (в chrome)
  • браузер говорит об CORS-ошибке, даже когда preflght запрос прошел, а реальный запрос отработал, но с ошибкой (например вернулась 500-ка, а она обычно возвращается без необходимых заголовков согласно CORS-у)
  • если отправив запрос с сайта А на сайт Б (не использующий HTTPS), сайт Б решит поставить куку на сайт Б, то браузер такую куку на сайт Б не сохранит, ошибки тоже не будет, но например chrome рядом с заголовком куки покажет желтый треугольник, который говорит, что так можно делать только когда сайт Б использует HTTPS.

Правило одного источника принцип обеспечения безопасности, реализованный web браузерами для предотвращения запросов JavaScript кодом к другим источникам (т.е. к другим доменам).

Cross-Origin Resource Sharing (CORS) является техникой для ослабления безопасности, которая разделяет запросы на 2 вида:

  • Простой - браузер сразу отправляет основной запрос
  • Сложный - сначала браузер отправляет OPTION-запрос (preflight), проверяет ответ и если все хорошо - отправляет основной запрос
  • Сложный с учетными данными пользователя в браузере - запрос осведомленный о файлах HTTP cookie и информации HTTP аутентификаци, такой запрос требует, чтобы на любой запрос отвечали хедером Access-Control-Allow-Credentials: true

Стандартный API

Api обычно не состоит из простых запросов, потому что например:

  • если Ваш запрос посылает например хеадер "Content-Type: application/json", то у Вас сложный запрос.
  • если Вы используете Cookies, то у Вас запрос сложный с учетными данными пользователя в браузере

Советую внимательно прочитать о каждом из запросов по ссылке выше, чтобы понимать, какими хедерами должен отвечать сервера на OPTION-запросы клиента.

Практика

Рассмотрим примеры каждого из видов запросов (запросы и ответы с необходимыми хедерами), где Client это js-код который выполняет запрос из браузера на домен отличный от текущего.

Простой

CORS просто

Сложный

CORS просто

Сложный с учетными данными пользователя в браузере

CORS просто

Чтобы совершить последний запрос (при котором на Server будут переданы учетные данные пользователя), Client при запросе обязан попросить браузера об этом с помощью параметра withCredentials, вот парочка примеров.

Пример js-кода:

var xmlhttp = new XMLHttpRequest();
xmlhttp.withCredentials = true; 
xmlhttp.open("POST", "http://server-b.com/login");
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(JSON.stringify({email:'user@example.com', password:'p@ssword'}))

Пример для выполнения запроса из консоли:

fetch("http://server-b.com/login", {
  "credentials": "include",
  "headers": {
    "accept": "application/json",
    "content-type": "application/json"
  },
  "body": "{email:'user@example.com', password:'p@ssword'}",
  "method": "POST",
  "mode": "cors"
});

тут "credentials": "include" это аналог withCredentials = true 

Как видно Выше, если server-b собирается устанавливать свои куки и считывать их, то server-b на все OPTION-запросы должен отвечать хедером Access-Control-Allow-Credentials: true

Интересные моменты

1. Если Client работает на домене с портом, например http://foo.example:8888, то порт должен быть указан в Access-Control-Allow-Origin: http://foo.example:8888

2. Только для простого запроса в Access-Control-Allow-Origin можно указывать * (указывая на доступность всем).

3. В примере выше, заголовок Access-Control-Max-Age указывает на то, что этот предполетный ответ действует 84600 секунд, после которого должен быть выполнен новый предполетный запрос.

4. Проверить: в то же время клиенту будет доступна отправка настоящего DELETE запроса к ресурсу.

5. Проверить: некоторые JavaScript библиотеки, такие как AngularJS или Sencha Touch, отправляют предполетные запросы на любой дочерний запрос. Этот подход пожалуй безопаснее, потому что он не предполагает, что сервис придерживается семантик HTTP метода (т.е. GET endpoint мог быть написана с побочными эффектами).

Cookies атрибуты

cookie_httponly = 1 : теперь cookies сессий не будут доступны через скриптовые языки, например JavaScript

Источник: 1 - 2 - 3 - 4 - 5


10.05.2018 06:27