15 Seconds : Sharing Cookies Across Domains

Tags: share, cookie, internet, issue, email

"(...) Sharing Cookies Across Domains By Wayne Berry Rating: 898 out of 5Rate this article document.write("<a href=http://www.internet.com/icom_cgi/print/print.cgi?url=" + window.location + ">print this article</a>") print this article email this article to a colleague suggest an article Introduction zzfocrender("203", "9508", "723954/677935/677920/581263/581034", "9", "300", "250", '', '', '');<a href="http://o1.qnsr.com/cgi/r?;n=203;c=723954/677935/677920/581263/581034;s=9508;x=2304;f=20111103091154;u=j;z=20111103091154;" target="_blank"><img border="0" width="300" height="250" src="http://o1.qnsr.com/cgi/r?;n=203;c=723954/677935/677920/581263/581034;s=9508;x=2304;f=20111103091154;u=j;z=20111103091154;" alt="Click here"></a> zzfocrender("203", "9508", "677940/677935/677920/581263/581034", "9", "300", "250", '', '', '');<a href="http://o1.qnsr.com/cgi/r?;n=203;c=677940/677935/677920/581263/581034;s=9508;x=2304;f=20111103091154;u=j;z=20111103091154;" target="_blank"><img border="0" width="300" height="250" src="http://o1.qnsr.com/cgi/r?;n=203;c=677940/677935/677920/581263/581034;s=9508;x=2304;f=20111103091154;u=j;z=20111103091154;" alt="Click here"></a> MARKETPLACEMom Turns $47 into $6795Local Mom spills secret on how she makes $6795/mo part time.ConsumerFinanceReviews.com /* creative ids to request pixel for */ /*1.3.2010 EGB: Added UM-MS Exchange */ var ib_creative_ids = [151225]; /*1.4.2010 EGB: Commented out due to current db issues */ /*,152116,152117];*/ /* function for url parsing */ var ib_parseurl = function (url) { var a = document.createElement('a'); a.href = url; return { source: url, protocol: a.protocol.replace(':',''), host: a.hostname, port: a.port, query: a.search, params: (function(){ var ret = {}, seg = a.search.replace(/^\?/,'').split('&'), len = seg.length, i = 0, s; for (;i<len;i++) { if (!seg[i]) { continue; } s = seg[i].split('='); ret[s[0]] = s[1]; } return ret; })(), file: (a.pathname.match(/\/([^\/?#]+)$/i) || [,''])[1], hash: a.hash.replace('#',''), path: a.pathname.replace(/^([^\/])/,'/$1'), relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [,''])[1], segments: a.pathname.replace(/^\//,'').split('/') }; }; /* function for building the template url */ var ib_request_impression = function (uid, vchannel, cid) { var uid_token = '[UID]'; var cid_token = '[CID]'; var vchannel_token = '[VCH]'; var impression_url = 'http://event.adxpose.com/event.flow?uid=[UID]&eventcode=000_000_12&location=&wh=&xy=&vchannel=[VCH]&cid=[CID]&duration=0&iframed=0&referer=&p=1'; impression_url = impression_url.replace(cid_token, cid); impression_url = impression_url.replace(uid_token, uid); impression_url = impression_url.replace(vchannel_token, vchannel); document.write('<img src="' + impression_url + '" border="0" width="1" height="1" />'); }; /* create associative array from creative ids for quick lookup */ var ib_creative_ids_hash = []; for (var i = 0; i < ib_creative_ids.length; i++) { ib_creative_ids_hash[ib_creative_ids[i]] = 1; } /* keep track of which creatives we've seen already to safe guard against duplicate impressions */ var ib_seen_creatives = []; /* loop through each url and check if we should request the impression url or not */ var ib_links = document.getElementsByName('iblink'); for (var i = 0; i < ib_links.length; i++) { var url = ib_parseurl(ib_links[i].href); var cid = url.params['cid']; if (ib_creative_ids_hash[cid] && !ib_seen_creatives[cid]) { ib_seen_creatives[cid] = 1; ib_request_impression( /* UID is the adXpose marchex id + creative id */ 'VJdObwjoojIh2szV_' + cid, /* VCHANNEL is our site id */ url.params['sid'], /* CID is the adXpose campaign id, (Marchex_Springboard in prod) */ /*'Marchex-Test' */ 'Marchex_Springboard' ); } } In this issue of 15 Seconds we will show you how to share the same cookie across multiple sub-domains and multiple domains. We will also discuss sharing state information across web farms using SQL Server. The examples in this issue highlight the power of redirection within Active Server page and enforce the concepts that are related to cookie manipulation. Sharing Cookies Between Sub Domains A sub-domain is a subset of the main domain that has a separate IP. For example, if you purchase the domain myserver.com from the INTERNIC you can break it down into sub domains like the following: www.myserver.com smtp.myserver.com client1.myserver.com secure.myserver.com You can issue a cookie on the www.myserver.com sub-domain like this: Example 1 <% Response.Cookies("UID")=1 %> This cookie will only last for the length of the user session, defined by the amount of time that browser stays open. The cookie's scope is just the www.myserver.com domain. If you request this cookie on other sub domains within the same domain you will not be able to get the value associated to UID. You can solve this problem by substituting the code in Example 2 for the code in Example 1. Example 2 <% Response.Cookies("UID")=1 Response.Cookies("UID").Domain = ".myserver.com" %> By setting the Domain property of the cookie to the domain of the sub domain you instruct the browser to send the cookie to all sub domains. Notice the period before the domain name, this is very important. RFC 2109 specifies that the Domain setting on cookies must have two periods. Sharing Cookies Between Domains Sharing cookies between domains is trickier then sharing cookies between sub-domains of a single domain. An example of this working is the three domains owned by Microsoft, msnbc.com, msn.com, and microsoft.com, these three domains share the same cookie for each user. To share a cookie between domains, you will need two domains, for example myserver.com and slave.com. One of the domains will issue the cookies and the other domain will ask the first domain what cookie should be issued to the client. In this case myserver.com will issue the cookie and slave.com will use the cookie issued by myserver.com. Here is the code that myserver.com will use to issue the cookie: Example 3 : cookie.inc <% UID=Request.Cookies("UID") If ((IsNull(UID)) OR (Len(UID)=0)) Then Set UIDGen=Server.CreateObject("SMUM.Example.1") 'Here is the method call to assign the cookie UID = UIDGen.GetCookie() Response.Cookies("UID")= UID Response.Cookies("UID").Domain=".myserver.com" Response.Cookies("UID").Expires = "December 31, 1999" End If %> The object created in this example was demonstrated in the Apr 22, 1997 issue of 15 Seconds entitled: "Active Server Components with VB 5.0." You can download just the object from this issue and use it in the code above. When the GetCookie method is called, a random 128-bit number is produced that is guaranteed to be unique to the user. UID stands for Unqiue IDentifer. Notice that this code is contained in a cookie.inc file that can be included at the top of all Active Server pages within the myserver.com domain. Requesting Cookie from Another Domain. Now the interesting part, how does slave.com get the same cookie from domain.com. This technique is implemented through a set of redirects. Let's take a look at the code that is implemented on slave.com Example 4 : getcookie.inc <% UID=Request.Cookies("UID") If ((IsNull(UID)) OR (Len(UID)=0)) Then strURL=Request.ServerVariables("URL")) strQueryString=Request.ServerVariables("QUERY_STRING")) If (Len(strQueryString)>0) Then strReturn= Server.URLEncode(strURL & "?" & strQueryString) Else strReturn= Server.URLEncode(strURL) End If Respone.Redirect("http://myserver.com/slave.asp?Return=" & strReturn) End If %> Notice that we do not actually assign the cookie in this page. Instead, if there is no cookie available we redirect to a special page on myserver.com. We also bundle up the address of the page we are on for future use. Let's take a look at slave.asp: Example 5 : slave.asp <!--#include virtual="/cookie.inc"--> <% strReturn=Server.URLEncode(Request("Return")) Response.Redirect("http://slave.com/return.asp?Return=" & strReturn & "&UID=" & UID) %> Notice that we included cookie.inc from Example 3. Since slave.asp resides on myserver.com the cookie that is issued in cookie.inc has a scope of just myserver.com. If the user didn't have a cookie on myserver.com they are given one, because of the code in cookie.inc. This way if they are visiting slave.com first and then visit myserver.com they will have the same cookie. If the user already has a cookie from myserver.com and they visit slave.com for the first time they will be redirected to slave.asp on myserver.com where that cookie will be retrieved. Because the cookie only has the scope of the domain that it is issued on we have to redirect to the master domain to get the cookie and then redirect back to the slave domain. Here is the code for return.asp which resides on slave.com. Example 6 : return.asp <% UID = Request ("UID") strReturn=Request("Return") Response.Cookies("UID")= UID Response.Cookies("UID").Domain=".slave.com" Response.Cookies("UID").Expires = "December 31, 1999" Response.Redirect(strReturn) %> Notice that return.asp sets the UID cookie to the UID that is passed from slave.asp on myserver.com. Because myserver.com passes the same UID as it uses for a cookie, both servers end up with the same cookie for the same user. In other words the user ends up with two cookies on their machine, one from myserver.com and one from slave.com, and they equal the same UID. Also note that the final redirect is back to the page the user requested on slave.com, the redirect uses the return information that the getcookie.inc bundled up. Return.asp should always be called from slave.asp and for no other reason. View Diagram In summary, every active server page should include getcookie.inc at the top of the page and if a cookie needs to be set getcookie.inc will handle the problem. Error Handling Because we wanted to make the examples easy to understand, we didn't add any error handle. However, if the client browser did not accept cookies, then the code demonstrated above would cause an endless loop of redirection. For this reason we need to change Example 6 to read: Example 7 : return.asp <% UID = Request ("UID") strReturn=Server.URLEncode(Request("Return")) Response.Cookies("UID")= UID Response.Cookies("UID").Domain=".slave.com" Response.Cookies("UID").Expires = "December 31, 1999" Response.Redirect("http://slave.com/test.asp?Return=" & strReturn) %> Now we can add test.asp which tests to make sure that the cookie took. Here is what the code looks like: Example 8 : return.asp <% UID = Request.Cookies("UID") If Not ((IsNull(UID)) OR (Len(UID)=0)) Then strReturn=Request("Return") Response.Redirect(strReturn) End If %> <HTML> <BODY> <H1>You must a browser that accept cookies on http://slave.com</H1> </BODY> </HTML> Performance If the user doesn't have a cookie from myserver.com and he requests a page that has cookie.inc included, they will be issued a cookie. This scenario is the best case scenario. If the user doesn't have a cookie from slave.com and he requests a page that has getcookie.inc included and they haven't visited myserver.com then they will have to undergo four redirects and be issued two cookies. This is the worst case scenario. Fortunately, the worst case scenario only happens once. All requests after that do not have to undergo any redirects. I (...)"