IE8 - головная боль в файлах cookie JSONP между доменами IE10

Из-за решений, которые полностью находятся вне моего контроля, я нахожусь в следующей ситуации:

  • У меня есть список товаров на catalog.org

  • Нажав кнопку "Добавить в корзину" на продукте, вы отправите AJAX JSONP-запрос к secure.com/product/add/[productKey], который сохранит запись корзины в базе данных, установит файл cookie с идентификатором корзины и вернет true ответ (или ложь, если это не удалось)

  • Вернитесь на catalog.org, если ответ верный, и отправьте другой запрос AJAX JSONP на secure.com/cart/info, который считывает куки-файл идентификатора корзины, выбирает запись и возвращает количество элементов в корзине.

  • Вернитесь на catalog.org еще раз, прочитайте ответ и обновите элемент на странице, показывающий количество товаров в корзине (если есть)

  • В этот момент, нажав кнопку "Перейти в корзину" на catalog.org, вы увидите сводную информацию о корзине на сайте secure.com.

Это прекрасно работает в Firefox 17, Chrome 32 и IE 11. Он также работает в IE8 - IE10 в наших средах разработки и тестирования, где catalog.org - это catalog.development.com, catalog.test.com и secure.com в безопасности. development.com и secure.test.com соответственно.

Однако после того, как мы развернули в производство, это перестало работать в IE8 - IE10. После добавления товара в корзину количество товаров в корзине успешно обновляется на catalog.org. Затем, после нажатия кнопки "Перейти в корзину" на catalog.org, в сводке корзины на secure.com ничего не отображается, потому что он не может прочитать cookie. Переход к Cache > "Просмотр информации о cookie" в инструментах IE develeoper не показывает cookie с идентификатором корзины. Он должен быть там, как и в других браузерах, в наших средах разработки и тестирования.

Я считаю, что IE блокирует сторонние куки. Мы добавили компактный заголовок политики P3P ко всем запросам на secure.com, но файл cookie все еще не установлен. Заголовок, который мы устанавливаем:

P3P: CP="CAO PSA OUR"

Почему добавление заголовка компактной политики не исправляет это в IE8 - IE10? Как я могу исправить это, чтобы работать во всех версиях IE?

Решение

Ниже приведены несколько хороших идей. Я принял @sdecima, потому что это звучало наиболее многообещающе. В итоге мы объединили некоторые из этих идей, но нам удалось избежать XDomainRequest:

  • Нажав кнопку "Добавить в корзину" на продукте, вы отправите AJAX JSONP-запрос к secure.com/product/add/[productKey], который сохранит запись корзины в базе данных, установит файл cookie с идентификатором корзины и вернет true ответ (или ложь, если это не удалось)

Мы изменили действие по адресу secure.com/product/add, чтобы оно возвращало объект JSON с логическим значением, указывающим на успех или неудачу, и идентификатором корзины.

  • Вернитесь на catalog.org, если ответ верный, и отправьте другой запрос AJAX JSONP на secure.com/cart/info, который считывает куки-файл идентификатора корзины, выбирает запись и возвращает количество элементов в корзине.

Мы изменили функцию обратного вызова, чтобы проверить оба свойства в объекте ответа. Если успех имеет значение true и идентификатор корзины присутствует, мы создаем скрытый iframe на странице. src для атрибута iframe установлена ​​новая конечная точка, которую мы добавили на secure.com. Это действие принимает параметр идентификатора корзины и сохраняет cookie идентификатора корзины. Нам больше не нужно сохранять cookie в действии secure.com/product/add.

Затем мы изменили действие по адресу secure.com/cart/info, чтобы принять параметр идентификатора корзины. Это действие будет использовать параметр ID корзины, если он присутствует, для получения информации о корзине, в противном случае он все равно будет пытаться прочитать cookie. Эта дополнительная проверка не потребовалась бы, если бы мы могли гарантировать, что iframe завершил загрузку и cookie были сохранены на secure.com, но у нас нет возможности узнать, когда iframe завершил загрузку на catalog.org из-за ограничений безопасности браузера.

Наконец, заголовок P3P CP="CAO PSA OUR" все еще требуется для этого, чтобы работать в IE7 - IE10. (Да, теперь это работает и в IE7:)

Теперь у нас есть решение (хотя и невероятно сложное) для сохранения и доступа к междоменным cookie-файлам, которое работает во всех основных браузерах, по крайней мере, настолько давно, насколько мы можем надежно протестировать.

Мы, вероятно, проведем этот рефакторинг еще немного. Во-первых, второй запрос AJAX JSONP к secure.com/cart/info на данный момент является избыточным, поскольку мы можем вернуть всю информацию, которая нам нужна в исходном запросе, для действия secure.com/product/add (побочное преимущество изменения это действие для возврата объекта JSON - плюс мы можем вернуть сообщение об ошибке, указывающее, почему оно не удалось, если произошла ошибка).

5 ответов

Решение

Короче

Куки-файлы НЕ будут проходить через перекрестный запрос в IE 8 и 9. Однако он должен работать в IE 10 и 11.


IE 8 и 9

В IE8/9 XMLHttpRequest частично поддерживает CORS, а перекрестные запросы выполняются с помощью объекта XDomainRequest, который НЕ отправляет файлы cookie с каждым запросом.

Вы можете прочитать больше об этом в следующем официальном блоге MSDN:
http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

Особенно эта часть:

5 Нет аутентификации или куки будут отправлены с запросом

Во избежание неправильного использования прав доступа пользователя (например, файлов cookie, учетных данных HTTP, клиентских сертификатов и т. Д.) Запрос будет очищен от файлов cookie и учетных данных и будет игнорировать любые проблемы аутентификации или директивы Set-Cookie в ответе HTTP. XDomainRequests не будут отправляться на ранее аутентифицированных соединениях, потому что некоторые протоколы аутентификации Windows (например, NTLM/Kerberos) основаны на соединении, а не на запросе.

IE 10+

Начиная с IE10, полная поддержка CORS была добавлена ​​в XMLHTTPRequest, и она должна нормально работать с правильным свойством заголовка Access-Control-Allow-Origin для ответа от сервера (который хочет установить cookie в браузере).

Подробнее об этом здесь:
http://blogs.msdn.com/b/ie/archive/2012/02/09/cors-for-xhr-in-ie10.aspx
И здесь:
http://www.html5rocks.com/en/tutorials/cors/

Методы обхода IE 8 и 9

Единственный способ обойти это в IE8/9 заключается в цитировании того же поста MSDN, что и выше:

Сайты, которые хотят выполнить аутентификацию пользователя для запросов из разных источников, могут использовать явные методы (например, токены в теле или URL-адресе POST) для передачи этой информации аутентификации, не рискуя окружающими правами пользователя.

Итог: сторонние куки обычно блокируются расширениями конфиденциальности / блокировки рекламы и должны считаться ненадежными. Вы будете стрелять себе в ногу, оставляя это в производстве.

Синтаксис предполагает, что конечная точка имеет амбиции, чтобы однажды стать RESTful. Единственная проблема с этим - использование куки, которые выбрасывают из окна всю концепцию "без сохранения состояния"! В идеале, изменения должны быть сделаны в API. Если вы не интегрируетесь с какой-либо третьей стороной (т. Е. "Secure.com" управляется вашей компанией), это абсолютно верный способ решения проблемы.

Переместить cartId из cookie-файла secure.com в свою строку запроса:

secure.com/product/add/9876?cartId=1234    //should be a POST

Где взять действительный cartId значение? Мы можем сохранить это в некоторых secure-com-cart-id cookie, установленный для домена каталога, что позволит избежать любых междоменных проблем. Проверьте это значение и, если оно присутствует, добавьте к каждому запросу secure.com, как указано выше:

$.post('secure.com/product/add/9876', {    //needs jQuery.cookie
  cartId: $.cookie('secure-com-cart-id')
});

Если у вас нет действующего cartId, относитесь к нему как к новому пользователю и делайте запрос без параметра. Ваш API должен затем назначить новый идентификатор и вернуть его в ответе. Местный" secure-com-cart-id печенье может быть обновлено. Промыть и повторить.

Вуаля, вы только что сохранили активную пользовательскую корзину, не загрязняя вызовы API cookie-файлами. Иди орать на своего архитектора. Если вы не можете сделать это (изменить синтаксис API или кричать), вам придется настроить туннель к конечной точке secure.com, чтобы не было междоменного запроса - в основном это что-то, находящееся по адресу catalog.org/secure-com-endpoint, который будет направлять запросы на secure.com дословно. Это обходной путь, специально предназначенный для того, чтобы избежать внесения изменений в API, просто не делайте этого с кодом и вместо этого установите надлежащие правила Apache/IIS/F5 для его обработки. Быстрый поиск приводит к нескольким объяснениям, это выглядит довольно хорошо для меня.

PS: это классическая проблема XY на мой взгляд. Решение не обязательно заключается в сохранении сторонних файлов cookie, а в передаче необходимых параметров третьим лицам при сохранении данных где-либо.

Если вы контролируете записи DNS, создайте новую запись, чтобы оба сервера находились в одном домене.

Хотя правильным решением было бы изменение архитектуры, если вы ищете быстрое временное решение:

Файлы JSONP на самом деле просто javascript. Вы можете добавить строку кода, чтобы установить куки в передней части вашего JSONP.

например, вместо:

callback({"exampleKey": "exampleValue"});

Ваш JSONP может выглядеть так:

document.cookie="cartID=1234";
callback({"exampleKey": "exampleValue"});

1 база данных обслуживает catalog.org и secure.com или они могут общаться?

Если так, то вы получили это.

Когда catalog.org выдает файл cookie, сохраните его в базе данных. Когда secure.com выдает файл cookie, сохраните его в БД. Затем вы можете определить, кому принадлежит какая корзина.

Это забавная проблема для рассмотрения...... Обновление 2:

Когда пользователь заходит на catalog.org:

  • проверьте, есть ли у него файл cookie cat_org, если нет, то:

    • в catalog.org:

      • создать пару ключ-значение и сохранить в db {cat_cookie_id, unique_number}
      • установить cat_cookie_id в браузере
      • поручить браузеру ajax посетить secure.com/register/unique_number
    • в secure.com

      • читать уникальный номер из URL
      • создать идентификатор secure_cookie
      • сохранить в БД {cat_cookie_id, unique_number, secure_cookie_id}
      • удалить unique_number, так как это одноразовый ключ

Теперь БД может сопоставить cat_cookie_id с secure_cookie_id и наоборот.

Другие вопросы по тегам