I am having requirement to navigate to third party site (SSO) from my application, this works well in chrome, IE9 and Firefox but not in safari. There was a workaround to have hidden iframe on page to set the cookie and then navigate to actual iframe, but this trick no longer works now. I also tried to open a new window with action as the third party URL to set cookie in the browser and then open the same in the iframe, but this has a disadvantage of that small window that is opened which looks like some hack. Is there any workaround to set the cookie in iframe for safari browser ??
问题:
回答1:
Introduction to tracking cookies
“Tracking cookies” is a very important part of online advertising ecosystem. They tons of usage scenarios. Here's one example called retargeting.
It's known that a lot of internet shoppers doesn't make purchase right after they saw a good deal on e-commerce website. They first choose a good, leave website and return in couple of hours or days to make an actual order.
To stimulate those users, websites utilize so-called retargeting technology. Basically, they want to remember users who left their website without making an order and show them a relevant advertisement on other websites. Typically e-commerce websites delegates such work to online advertisement platforms, like AdExchanges, DSPs and so on.
From, technical point of view it works as follows:
Website owner puts a small piece of HTML code. The piece of code is called "tracking pixel". Let's consider a simple case when the tracking pixel is a transparent GIF image:
...
<img src="http://pixel.sample-ad-exchange.com/pixel.gif">
..http://pixel.sample-ad-exchange.com/pixel.gif
drops a cookie for domain '.sample-ad-exchange.com' with name user_id. In this cookie a generated unique user id is stored (If the cookie already exists, server just skips this part)sample-ad-exchange.com remembers internally that user with this id visited e-commerce site
When sample-ad-exchange.com is requested to show an ad somewhere else (by calling tag.sample-ad-exchange.com/show_ad.js for example) it receives user_id cookie along with http request
sample-ad-exchange.com checks internally if this user visited any e -commerce sites before. If he has, it could show a very relevant ad to him
The problem
As you can see, ability to drop cookie is the viable part of retargeting scheme. This kind of cookies is called "3rd party cookies" because pixel code is sitting on advertiser domain (e.g. my-cool-store.com), and pixel itself is located on 3rd-party ad-exchange domain (.sample-ad-exchange.com). By default, different browsers have different policy about 3rd party cookies.
Chrome, Firefox, IE before 8.0 - always accept 3rd party cookies
IE 8.0 and above - accept 3rd-party cookie only if website explicitly declared how it will use the cookies. The declaration is done via P3P protocol. As every spec from W3C, this one is also very cryptic. But the essence is the HTTP header called "P3P" that you need to send along with http response containing cookie. This header content works fine though I have no idea what's exactly it's declaring: 'P3P: CP="NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA"'
Safari - never accepts 3rd party cookies
Safari wasn't a huge problem for industry before iPad appeared and gained huge popularity. Studies shows that iPad users tend to shop online even more than usual PC guys.
Trick 1.0 (not working anymore)
In fact Safari sometimes doesn't reject 3rdparty cookies. It happens than user did some action related to 3rdparty domain. Google Analytics (and other platforms too) took advantage of this feature: they inserted an iframe and simulated form sumbit inside it. I won't stop on technical details here. First, this hack cost google $22.5 millions and second the trick isn't working anymore in last versions of Safari
Trick 2.0 (HTML5 localStorage)
The idea of this trick is use HTML5 localStorage API. This API is very similar to cookies - it allows managing user’s preferences from javascript and storing it locally on user's box. Why not store user id in localStorage? The first version of code I came up with:
<script type="text/javascript">
if (typeof navigator != "undefined" && typeof navigator.vendor != "undefined" && navigator.vendor.indexOf("Apple") >= 0 && typeof localStorage != "undefined") {
//Check if browser is made by Apple (means it's Safari) and local storage is available
var userId = localStorage.getItem("user_id");
if (userId == null) {
//set user is if user is unknown
userId = Math.random();
localStorage.setItem("user_id", userId);
}
var img = document.createElement('img');
img.src = "http://pixel.sample-ad-exchange.com/pixel.gif?user_id=" + user_id;
var body = document.getElementsByTagName('body')[0];
body.appendChild(img);
}
The idea is pretty straightforward: look for user_id key in local storage (create one if it doesn't exist) and pass user_id to pixel server as GET parameter. Then server will record this id instead firing the cookie.
But this code isn't working well. Each domain has it's own local storage. And if you tracking pixel was fired at my-cool-store.com user_id will be stored in my-cool-store.com local storage. If the same user would visit other-domain.com with tracking code later on it will be treated as new one.
To fix that old good trick with iframe will work. Instead of img tag we will insert iframe tag with source somewhere inside pixel.sample-ad-exchange.com. And place user detection code inside iframe. As iframe is executed "inside" pixel.sample-ad-exchange.com local storage will be the same for all tracked sites. Here's a complete example:
Tracking code:
<script type="text/javascript">
if (typeof navigator != "undefined" && typeof navigator.vendor != "undefined" && `navigator.vendor.indexOf("Apple") >= 0 && typeof localStorage != "undefined") {`
var iframe = document.createElement('iframe');
img.src = "http://pixel.sample-ad-exchange.com/iframe.html";
var body = document.getElementsByTagName('body')[0];
body.appendChild(img);
}
</script>
Iframe code (http://pixel.sample-ad-exchange.com/iframe.html
)
<html>
<head></head>
<body>
<script type="text/javascript">
var userId = localStorage.getItem("user_id");
if (userId == null) {
//set user is if user is unknown
userId = Math.random();
localStorage.setItem("user_id", userId);
}
var img = document.createElement('img');
img.src = "http://pixel.sample-ad-exchange.com/pixel.gif?user_id=" + user_id;
var body = document.getElementsByTagName('body')[0];
body.appendChild(img);
</script>
</body>
</html>
Legal issue
The interesting question is if this method is legal. Znd if next company using it will get $22.5 million fine. I'm not a lawyer, but from my common sense perspective as Safari settings explicitly says "Block thirdparty cookies from third parties and advertisers" and localStorage isn't a "cookie" the approach above seems legit.
回答2:
Hidden (or not hidden !) iframes won't work, since they would still violate the same-origin policy.
Try searching for CORS - "Cross Origin Resource Sharing". It's a standard that is now implemented in all major browsers.