2017-02-17 2 views
4

Я не могу получить Safari для успешного применения Set-Cookie ответов сервера при использовании Fetch API (фактически, через fetch polyfill). Тот же код работает правильно в FF и Chrome (я тестировал с использованием как native, так и polyfill fetch).Safari, не устанавливающий Cookies CORS, используя API-интерфейс JS Fetch

  1. Запрос осуществляется через домены;
  2. да, я устанавливаю credentials: true;
  3. сервер отвечает на заголовок Set-Cookie;
  4. последующие запросы отправляются из Chrome и FF с заголовками запросов файлов cookie, но Safari этого не делает;
  5. запрос использует HTTPS (сертификат самоподписанный и в домене разработки, но, по-видимому, он принят Safari на регулярных запросах); и

Кто-нибудь знает, в чем проблема?

Я прочитал документацию и прошел через многие из closed bug reports. Если я что-то пропустил, я думаю, может быть, проблема связана с 'default browser behaviour', касающейся файлов cookie и CORS, - а не с помощью fetch (чтение через исходный код polyfill, похоже, на 100% игнорируется куки). Несколько отчетов об ошибках свидетельствуют о том, что неправильный ответ сервера может предотвратить сохранение файлов cookie.

Мой код выглядит следующим образом:

function buildFetch(url, init={}) { 
    let headers = Object.assign({}, init.headers || {}, {'Content-Type': 'application/json'}); 
    let params = Object.assign({}, init, { credentials: 'include', headers }); 

    return fetch(`${baseUrl}${url}`, params); 
} 

buildFetch('/remote/connect', {method: 'PUT', body: JSON.stringify({ code })}) 
.then(response => response.json()) 
.then(/* complete authentication */) 

запрос Фактическое разрешение ниже. Я использую cURL для получения точных данных запроса/ответа, так как Safari затрудняет его копирование и вставку.

curl 'https://mydevserver:8443/api/v1/remote/connect' \ 
-v \ 
-XPUT \ 
-H 'Content-Type: application/json' \ 
-H 'Referer: http://localhost:3002/' \ 
-H 'Origin: http://localhost:3002' \ 
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/602.4.8 (KHTML, like Gecko) Version/10.0.3 Safari/602.4.8' \ 
--data-binary '{"token":"value"}' 


* Trying 127.0.0.1... 
* Connected to mydevserver (127.0.0.1) port 8443 (#0) 
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 
* Server certificate: mydevserver 
> PUT /api/v1/remote/connect HTTP/1.1 
> Host: mydevserver:8443 
> Accept: */* 
> Content-Type: application/json 
> Referer: http://localhost:3002/ 
> Origin: http://localhost:3002 
> User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/602.4.8 (KHTML, like Gecko) Version/10.0.3 Safari/602.4.8 
> Content-Length: 15 
> 
* upload completely sent off: 15 out of 15 bytes 
< HTTP/1.1 200 OK 
< Access-Control-Allow-Origin: http://localhost:3002 
< Access-Control-Allow-Credentials: true 
< Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Api-Key, Device-Key 
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS 
< Access-Control-Expose-Headers: Date 
< Content-Type: application/json; charset=utf-8 
< Content-Length: 37 
< Set-Cookie: express:sess=[SESSIONKEY]=; path=/; expires=Fri, 17 Feb 2017 15:30:01 GMT; secure; httponly 
< Set-Cookie: express:sess.sig=[SIGNATURE]; path=/; expires=Fri, 17 Feb 2017 15:30:01 GMT; secure; httponly 
< Date: Fri, 17 Feb 2017 14:30:01 GMT 
< Connection: keep-alive 
< 
* Connection #0 to host mydevserver left intact 
{"some":"normal","response":"payload"} 

ответ

6

Отвечая на мой вопрос.

Я нахожу это довольно раздражающим, что это «работающее по назначению» поведение Safari, хотя я понимаю их мотивацию. XHR (и, предположительно, нативный выбор, когда он приземляется изначально) не поддерживает настройку сторонних файлов cookie. Этот сбой полностью прозрачен, потому что он обрабатывается браузером вне контекста сценариев, поэтому решения на основе клиента на самом деле не будут возможны.

Рекомендуемое решение, которое вы найдете здесь, - это открыть окно или iframe на странице HTML на сервере API и установить там файл cookie. На этом этапе начнут работать сторонние файлы cookie. Это довольно уродливо, и нет никакой гарантии, что Safari в какой-то момент не будет закрывать эту лазейку.

Мое решение состоит в том, чтобы в основном переопределить систему аутентификации, которая делает то, что делает сеанс-куки.А именно:

  1. Добавить новый заголовок, X-Auth: [token], где [token] является очень маленьким, недолгим JWT, содержащий информацию, которую требуется для сеанса (в идеале только идентификатор пользователя - то, что вряд ли мутировать во время срок службы вашего приложения - но определенно не что-то вроде прав доступа, если разрешения могут быть изменены во время сеанса);
  2. Добавить X-Auth - Access-Control-Allow-Headers;
  3. Во время входа установите cookie сеанса и токен аутентификации с необходимыми полезными нагрузками (как пользователи Safari, так и не-Safari получат как cookie, так и заголовок auth);
  4. На клиенте найдите заголовок ответа X-Token и повторите его как заголовок запроса X-Token в любое время, когда он его видит (вы можете добиться сохранения с помощью локального хранилища - срок действия токена истекает, так что даже если значение живет годами , он не может быть погашен после определенного момента);
  5. На сервере для всех запросов на защищенные ресурсы проверьте наличие файла cookie и используйте его, если он существует;
  6. В противном случае (если файл cookie отсутствует - поскольку Safari его не отправил), найдите токен заголовка, проверьте и расшифруйте полезную нагрузку маркера, обновите текущий сеанс с предоставленной информацией и затем сгенерируйте новый токен аутентификации и добавьте его в заголовки ответов;
  7. Действуйте как обычно.

Обратите внимание, что JWT (или что-то подобное) предназначено для решения совершенно другой проблемы и никогда не должен использоваться для управления сеансом из-за проблемы с воспроизведением (подумайте, что может произойти, если у пользователя открылось два окна с собственным заголовком). В этом случае, однако, они предлагают вам быстроту и безопасность. В нижней строке вы должны использовать куки-файлы в браузерах, которые их поддерживают, сохраняйте информацию о сеансе как можно меньше, держите JWT как можно короче, и создайте серверное приложение, чтобы ожидать как случайных, так и вредоносных атак.

Смежные вопросы