Настройка междоменных файлов cookie в Safari

Я должен позвонить домен A.com (который устанавливает куки с http) с домена B.com. Все, что я делаю на домене B.com, это (javascript):

var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.src = "A.com/setCookie?cache=1231213123";
head.appendChild(script);

Это устанавливает cookie на A.com во всех протестированных мной браузерах, кроме Safari. Удивительно, но это работает в IE6, даже без заголовков P3P.

Есть ли способ заставить это работать в Safari?

Ответ 1

Из Safari Developer FAQ:

Safari поставляется с консервативной политикой файлов cookie, которая ограничивает запись файлов cookie только выбранными страницами ( "navigated to" ) пользователем. Эта консервативная политика по умолчанию может путать сайты на основе фреймов, которые пытаются писать файлы cookie и терпят неудачу.

Я не нашел способа обойти это.

Если это того стоит, Chrome не устанавливает файлы cookie, если вы используете метод добавления <script > , но если у вас есть скрытый <img > с тем же источником, Chrome работает в дополнение к остальной части браузеры (кроме, опять же, Safari)

Ответ 4

Есть немного злая трюка, предполагая, что у них установлена ​​вспышка.

Я не уверен, работает ли он по-прежнему, но Flash'es "Локальные общие объекты", ака Flash Cookies, может помочь вам совершить кругосветку политик в одном домене Safari.

Учебник по локальному общему объекту

Однако, по меньшей мере, это может быть сложно реализовать.

Кроме того, LSO отправляются в свет как кошмар безопасности:

Поэтому тщательно подумайте, прежде чем использовать их.

Ответ 5

Сообщение для скрытого <iframe> может позволить вам обходить это ограничение в Safari - http://gist.github.com/586182:

<?php
  header('P3P: CP=HONK');
  setcookie('test_cookie', '1', 0, '/');
?>
<div id="test_cookie" style="position: absolute; top: -10000px"></div>
<script>
  window.setTimeout(function() {
    if (document.cookie.indexOf('test_cookie=1') < 0) {
      var      
        name = 'test_cookie',
        div = document.getElementById(name),
        iframe = document.createElement('iframe'),
        form = document.createElement('form');

      iframe.name = name;
      iframe.src = 'javascript:false';
      div.appendChild(iframe);

      form.action = location.toString();
      form.method = 'POST';
      form.target = name;
      div.appendChild(form);

      form.submit();
    }
  }, 10);
</script>

Ответ 6

Существует соответствующее обходное решение для этой работы в 2015 году. Скажем, есть веб-сайт y.com, который включает iframe с сайтом x.com. X.com iframe хочет сохранить файл cookie. Это не разрешено политикой Safari, однако y.com может ее хранить. Поэтому y.com должен прослушивать сообщения с сайта x.com, а затем сохранять сам файл cookie.

var _cookieEvMth = window.addEventListener ? "addEventListener" : "attachEvent";
var _cookieEvAction = window[_cookieEvMth];
var _cookieEv = _cookieEvMth == "attachEvent" ? "onmessage" : "message";
_cookieEvAction(_cookieEv, function(evt){
  if(evt.data.indexOf('cookieset')!=-1){
    var datack = evt.data.split('|');
    YOUR_CUSTOM_COOKIE_SAVE_METHOD(datack[1],datack[2],datack[3]);
  }
},false);

Когда x.com необходимо сохранить файл cookie, он должен отправить сообщение на y.com:

window.parent.postMessage('cookieset|'+ckName+'|'+ckVal+'|'+days,'*');

Также вы можете поработать над отправкой сообщения в iframe, если хотите прочитать cookie. Или вы можете включить его в качестве параметра в URL-адрес if.com if.com, используя javascript:

iframe.setAttribute('url','x.com/?cookieval='+YOUR_COOKIE_GET_METHOD('cookiename'));

Ответ 7

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

Итак, суть в том, что мы сделали:

  • Пользователь нажимает на ссылку с сайта B.com
  • Всплывающее окно открывается в A.com/setCookie
  • A.com устанавливает свой файл cookie, а затем перенаправляет на B.com в нужном месте

Опять же, недействителен во всех решениях, но он работал в нашей. Надеюсь, это поможет.

Ответ 8

Я знаю, что этот вопрос довольно старый, но это помогло мне решить проблему куки:

var cookieForm = document.createElement("form");
cookieForm.action = "A.com/setCookie?cache=1231213123";
cookieForm.method = "post";
document.body.appendChild(cookieForm);

cookieForm.submit();

Идея сделать сообщение формы на странице, которая устанавливает ваши файлы cookie.

Ответ 9

* ИЗМЕНИТЬ * Об этом обходное решение было опубликовано в WebKit закрыто.

Лука,

Хорошо, поэтому этот ответ - два года, но... вы можете установить cookie из iframe, если вы отправляете форму в скрытый iframe. Вы можете сделать это, создав форму:

<form id="myiframe" action="http://yourdomain.com" method="POST" target="iframe_target">

Затем в Javascript получить ссылку на форму и отправить submit:

document.getElementsByTagName('form')[0].submit();

Вы можете прослушивать iframe onload, или вы можете заставить свою страницу действия iframe выдать некоторый javascript, который сигнализирует о загрузке. Я тестировал это в Safari и Chrome, и он работает.

Приветствия.

Ответ 10

Это может не работать для всех, но я столкнулся с этой проблемой, потому что я обслуживал React App с другого хоста, чем API, и решение, которое в конечном итоге сработало, заключалось в использовании DNS:

Наш клиент обслуживался с www.company-name.com, а наш API был на company-name.herokuapp.com. Сделав запись CNAME api.company-name.com → company-name.herokuapp.com и предложив нашему клиенту использовать этот поддомен для вызовов API, Safari перестала считать его "сторонним" файлом cookie.

Плюс в том, что задействовано очень мало кода, и все это использует хорошо зарекомендовавшие себя вещи. Минус в том, что вам нужен некоторый контроль/владение хостом API, если вы собираетесь использовать https - им нужен действительный сертификат для клиентского домена, или пользователи получат предупреждение сертификата - так что это не сработает (по крайней мере, не для конечного пользователя), если рассматриваемый API не ваш или партнерский.

Ответ 11

Возможно, прагматически создайте и щелкните ссылку с href="A.com/setCookie?cache=1231213123" и атрибут target, указывающий на скрытый iframe. Это может обойти политику Safari для навигации пользователей для настройки файлов cookie (у меня нет Safari для тестирования.)

Ответ 12

Я провел некоторое подробное исследование по этому вопросу, когда пытался развернуть сайт, на котором использовался идентификатор Windows Live ID, который зависел от способности устанавливать сторонние файлы cookie для выхода из системы. Это просто... не сработало. Ничто из того, что мы могли бы сделать, не заставит его работать. Команда Live ID также провела обширное расследование, и их ответ был "не может заставить его работать".

Ответ 13

Обратите внимание на эту строку:

script.src = "A.com/setCookie?cache=1231213123";

Я не мог получить эту работу, пока не добавлю http, т.е.

script.src = "http://A.com/setCookie?cache=1231213123";

Ответ 14

Я нашел простое решение. Вам просто нужно сначала установить cookie, чтобы проверить, пришел ли запрос из того же источника или нет, если не как обычно вам нужно вернуться в iframe a script, который повторит этот запрос, уже имеющий разрешение на назначение файла cookie. После этого вы можете выполнить другой запрос напрямую через iframe, чтобы получить доступ к этому файлу cookie. Это помогло мне в моей системе слежения. Попробуйте, это хорошо работает.

Ответ 15

Стоит отметить, что это ограничение в Safari не распространяется на субдомены. Поэтому, если вы заходите на сайт sitea.com напрямую, вы можете устанавливать файлы cookie с subdomain.sitea.com без прямого взаимодействия с пользователем (iframe/JavaScript).

Это было актуально для моего случая при разработке API. Если ваши посетители приходят на mysite.com, а затем вы хотите, чтобы какой-то JavaScript взаимодействовал с вашим API, то если API размещен на api.mysite.com, он будет работать в Safari.

Ответ 16

Разместите этот JavaScript на странице, выполняющей междоменные запросы, http://example1.com/index.html:

  <script>
  var gup = function(name, url) {
     if(!url) url = location.href;
     name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
     var regexS = "[\\?&]"+name+"=([^&#]*)";
     var regex = new RegExp( regexS );
     var results = regex.exec( url );
     return results == null ? null : results[1];
  }
  var isSafari = navigator.vendor && navigator.vendor.indexOf('Apple') > -1 && navigator.userAgent && !navigator.userAgent.match('CriOS');
  var n = gup("activated");
  if(isSafari && n == null) {
     //browser is Safari and cookies have not yet been activated
     var current_url = location.protocol + '//' + location.host + location.pathname;
     var query_string = '?callback=' + encodeURIComponent(current_url + '?activated=1');
     var new_url = 'http://example2.com/activate.php' + query_string;
     window.location.href = new_url;
  }
  //the rest of your code goes here, and you can now set cross-domain cookies on Safari
  </script>

Затем создайте файл на другом сервере, для которого необходимо установить файлы cookie, http://example2.com/activate.php:

  <?php
  if(isset($_GET['callback'])) {
     header('Location: '.$_GET['callback']);
     exit();
  } else {
     //in case callback param is not set, simply go back to previous page
     echo "<script>";
     echo "window.history.back();";
     echo "</script>";
     exit();
  }
  ?>

Вот как это работает:

  1. При первом посещении http://example1.com/index.html выполняется проверка, чтобы определить, является ли браузер Safari и не существует ли параметр GET с именем "active". Если оба условия соблюдены (что произойдет при первом посещении браузера Safari), то браузер будет перенаправлен на http://example2.com/activate.php с параметром GET "callback", содержащим добавленный вызывающий URL-адрес. с "активированным" параметром.

  2. http://example2.com/activate.php просто перенаправляет обратно на URL-адрес, содержащийся в параметре GET, "обратный вызов".

  3. Когда http://example1.index.html теперь выполняется во второй раз после перенаправления, теперь будет задан параметр GET "active", поэтому условие с шага 1 не будет выполнено, что позволит сценарию продолжить выполнение.

Это соответствует требованию Safari о том, чтобы браузер хотя бы раз посещал сторонний домен, чтобы начать установку файлов cookie.

Ответ 17

У меня была эта проблема, и этот фрагмент кода решил ее:

setcookie("cookie_name", $cookie_value, time()+(60*60*24*365), "/", ".domain.com", "", false);

setcookie("cookie_name", $cookie_value, time()+(60*60*24*365), "", "", "", false);

Теперь это видно и из других поддоменов в сафари. Я не знаю, почему для работы нужно установить два куки, но это так.

Ответ 18

Попробуйте что-то вроде:

var w = window.open("A.com/setCookie?cache=1231213123");
w.close();

Он может обойти политику безопасности сафари.

Ответ 19

Это не недостающий атрибут типа, который вас раздражает? -)

<script type="text/javascript">
  var head = document.getElementsByTagName("head")[0];
  var script = document.createElement("script");
  script.setAttribute("type","text/javascript");
  script.src = "A.com/setCookie?cache=1231213123";
  head.appendChild(script);
</script>