Файлы cookie недоступны в JavaScript (и инструментах разработки) , но отправляются вместе с запросом XHR (не используется httponly)

я использую как интерфейсное, так и серверное приложение в другом домене с авторизацией на основе сеанса. У меня есть настройка рабочей конфигурации CORS, которая работает так, как ожидалось на localhost (например, из порта :9000 в порт :8080). Как только я развертываю приложения на защищенных доменах (оба домена разрешают только HTTPS), файл cookie CSRF больше не доступен в JavaScript, что приводит к неправильному последующему запросу интерфейса (отсутствует CSRF заголовок.)

файл cookie устанавливается задней частью в Set-Cookie заголовок без С помощью HttpOnly флаг. Он фактически установлен где-то в браузере, потому что последующий запрос содержит как файл cookie сеанса, так и файл cookie CSRF. Попытка доступа к нему с помощью JavaScript (например,document.cookie в консоли) возвращает пустую строку. DevTools Chrome не показывают любой cookies на интерфейсном домене (внутренний домен даже не перечисленный.)

Я ожидаю, что cookie будет установлен и будет виден в текущем домене (интерфейсный домен). Я использую withCredentials флаг axios библиотека.

у вас есть идеи, почему файл cookie не может быть доступен из JavaScript или из DevTools в Chrome? Имеет ли это какое-либо отношение к Strict-Transport-Security заголовок?


заголовки

1. Первоначальный ответ GET Заголовок

HTTP/1.1 401 Unauthorized
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://[my-frontend-domain]
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Encoding: gzip
Content-Type: application/json;charset=UTF-8
Date: Wed, 20 Sep 2017 11:57:07 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: CSRF-TOKEN=[some-token]; Path=/
Vary: Origin,Accept-Encoding
X-Content-Type-Options: nosniff
X-Vcap-Request-Id: [some-token]
X-Xss-Protection: 1; mode=block
Content-Length: [some-length]
Strict-Transport-Security: max-age=15768000; includeSubDomains

2. Заголовок последующего запроса POST

POST /api/authentication HTTP/1.1
Host: [my-backend-host]
Connection: keep-alive
Content-Length: [some-length]
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/plain, */*
Origin: [my-frontend-host]
User-Agent: [Google-Chrome-User-Agent]
Content-Type: application/x-www-form-urlencoded
DNT: 1
Referer: [my-frontend-host]
Accept-Encoding: gzip, deflate, br
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4,de-CH;q=0.2,it;q=0.2
Cookie: [some-other-cookies]; CSRF-TOKEN=[same-token-as-in-the-previous-request]

этот запрос должен содержать заголовок CSRF, который будет автоматически добавлен, если файл cookie доступен с помощью JavaScript.

4 ответов


короче говоря, невозможно получить доступ к куки-файлам cross-origin,document.cookie доступ только к текущему (или родитель) доменные cookies.

намек на то, что это является основной причиной, был SSC-hrep3, упоминая "оба домена" в своем вопросе.

очень легко сделать эту ошибку при переключении с развертывания localhost, используя только разные порты для серверных и интерфейсных серверов, на тот, который использует два разных хоста. Это будет работать локально, потому что cookies являются общими для всех портов и не будут работать при использовании двух разных хостов. (В отличие от некоторых других проблем CORS, которые также будут отображаться локально)

посмотреть ответ ssc-hrep3 для получения дополнительной информации и решения.


1

вам может потребоваться добавить Управление Доступом-Разрешить-Заголовки заголовок, чтобы разрешить передачу определенных заголовков.

пожалуйста, попробуйте добавить следующее в заголовки ответов сервера (метод опций) для целей тестирования

Access-Control-Allow-Headers: Content-Type, *

в производстве я рекомендую ограничить заголовки следующим образом (но я не уверен на 100% в правильном списке заголовков, нужно экспериментировать здесь, если это работает)

Access-Control-Allow-Headers: Cookie, Set-Cookie

для справки https://quickleft.com/blog/cookies-with-my-cors/

2

еще одна проблема, которую вы можете experince является то, что вы cookies будут установлены на том домене, где находится ваш серверный сервис (не в домене, из которого вы запрашиваете)

пожалуйста, проверьте это

3

в качестве опции последней проблемы-браузер может запретить установку cookie для домена b.xxx.com запрос, который приходит от a.xxx.com

в этом случае вы можете попробовать установить cookie в Родительском домене xxx.com, поэтому он будет доступен для вашей стороны клиента


TL; DR: чтение-доступ к междоменным cookies невозможен. Добавление токена CSRF в заголовок ответа было бы решением. Другим решением для полного обхода CORS & междоменных запросов было бы использование обратного прокси-сервера.


как указано в моем вопросе выше, часть JavaScript моего интерфейса (например,https://example1.com пытается получить доступ к не-HttpOnly cookie из моего бэк-энда, например https://example2.com. Чтобы иметь доступ к a удаленный API с JavaScript, я использую CORS. Это позволяет выполнять запросы. Я использую withCredentials: true на лицевой стороне и Access-Control-Allow-Credentials: true на задней стороне. The Set-Cookie заголовок затем устанавливает файл cookie на внутреннем источнике, а не на интерфейсном источнике. Поэтому cookie не отображается ни в DevTools, ни в document.cookie команда в JavaScript.

Cookies, установленные на back-end origin, всегда являются частью запроса к back-end через CORS. Однако мне нужен доступ. к контент файла cookie CSRF для добавления маркера в заголовок запроса (для предотвращения атак CSRF). Как я узнал, нет способа читать (или писать) куки из другого домена с помощью JavaScript-независимо от того, какая настройка CORS используется (см. эти ответы StackOverflow: [1], [2]). Браузер ограничивает доступ к содержимому файла cookie для одного и того же домена.

решений

это приводит к выводу,, что нет возможности получить доступ к содержимому безHttpOnly cookie другого домена. Обходным путем для этой проблемы было бы установить токен CSRF в дополнительный пользовательский заголовок ответа. Эти заголовки обычно также не могут быть доступны в другом домене. Однако они могут быть подвержены настройке CORSAccess-Control-Expose-Headers. Это безопасно, пока используется строго ограниченный Access-Control-Allow-Origin заголовок.

другим обходным путем было бы использование обратного прокси-сервера, который обходит проблемы с CORS и междоменными запросами вообще. Использование такого обратного прокси обеспечивает специальный путь на интерфейсе, который будет перенаправлен на серверную часть. Например, вызовы https://front-end/api прокси для https://back-end/api. Поскольку все запросы от интерфейсного сервера выполняются к интерфейсному прокси-серверу в том же домене, браузер рассматривает каждый вызов как запрос того же домена, а куки-файлы устанавливаются непосредственно в интерфейсном источнике. Недостатки этого решения включают потенциал проблемы с производительностью из-за того, что другой сервер находится между (задержки) и куки-файлы должны быть установлены на двух источниках (войти дважды при прямом доступе к задней части). Настройка обратного прокси-сервера может быть выполнена с помощью nginx, apache или очень легко с помощью http-proxy-middleware в узел.js:

var express = require('express');
var proxy = require('http-proxy-middleware');

var options = {
	target: 'https://[server]',
	changeOrigin: true,
	secure: true
};

var exampleProxy = proxy(options);
var app = express();

app.use('/api', exampleProxy);
app.use(express.static(__dirname + "/public"));
app.listen(process.env.PORT || 8080);

Как вы можете прочитать здесь спецификация XHR и explictily запрещает чтение набор-печенье. Лучший способ сделать это-передать информацию в заголовке вместо файла cookie.