views:

631

answers:

11

Hi, we are solving the problem with eshop (php, mysql). The client want to have the same eshop on two domains with shared shopping cart. In the shop customer can do the shopping without users account (can't be logged in). And there is the problem, how to make the shared shopping cart cross domain.

The data from cart is stored in sessions, which we stored in database too. But we can't solve the problem in carrying data over domains. Identifying unlogged user is not holeproof (research).

The example, how it should work

Customer goes to domainOne and add some things to the cart. Than he goes to domainTwo (by link, typing domain address, however) and add some other things to the cart. In the cart he has things from both domains (after refreshing page).

Do you have any idea, how to solve this problem?

What didn't work:

  • redirecting is not possible due to customer requirments
  • cookies are related to domain
  • set_cookie with the other domain didn't work
  • the simpliest way is to carry over only the sessionid (stored in cookies) but we don't know, how to wholeproof identify unlogged users.
  • is there any other place, where data can be stored on client side except cookies? (probably not)
  • we can't use sending sessionid by params in url (if user click to link to the other domain) or resolving the header referer, bcs we don't know, how user can achieve the other domain.

If you can't understand me, take me a question. If you think, that having eshop on two domains with shared (common) cart is bad idea, don't tell me, we know it.

Thanks for each answer.

+3  A: 

This keeps getting asked.

Have a search for SSO.

You need to pass the session id in the URL (or vai a POST) across the domains, then:

1) check the session does not already exist on the target domain

2) rebind the session using the session id sent

e.g.

if ((!$_COOKIE[session_name()]) && $_GET['passed_id']) {
    if (check_session_exists($_GET['passed_id'])) { 
        session_id($_GET['passed_id']);
    }
}
session_start();
...
function check_session_exists($id)
{
   $path=session_save_path() . $id;
   if (file_exists($path) && (time()-filemtime($path)<session_cache_expire())) {
      return true;
   }
   return false;
}

This also means you need to add '?passed_id=' . urlencode(session_id()) to any URL pointing to the other domain.

C.

symcbean
We know this way, but we can't guarantee adding sessid to each url. And what about situation: customer has opened two browser tabs and adding things to cart simultaneously? So - we can't carry over the sessid in url.
Jaroslav Moravec
Then you can't have cross domain baskets. End of story.
symcbean
Sounds like an invitation for session fixation.
Tgr
@Tgr: if you're refering to my post above....I can't see how (note I said to **only** use the passed parameter as the session id **if** that session already exists).
symcbean
Still dangerous. The attacker can open a session, trick someone into jumping into that session, then use the session himself e.g. to change the order address in the last second. Setting the session id from a GET parameter is not necessarily a vulnerability, but makes it very easy to slip up. (Though that will be probably true for other cross-domain basket schemes as well.)
Tgr
Anyway, it isn't true that you need session id visibly in the URL to make cross-domain baskets work; there are a lot of ways around that. To name just one: whenever you are starting a new session, put an image into the page footer, set a script in the other domain as its source, and pass the session id as a parameter. The script then starts a session with the same sessionid on the other domain, and returns an invisible pixel.
Tgr
A: 

SSO.

CartA has iframe that 1) checks if the user is "active" (has session) 2) creates anon session CartB has iframe that do 1) or 2)

iframe loads from SSO domain (any domain you can have)

SSO solution: build yours or use others - like simplesamlphp or something...

And there should be no need to pass sessions/params with URIs...

f13o
A: 

You can store data in other places than cookies (e.g. Flash cookies, localStorage) but all use same origin policy, which is the standard security model of the web: data stored by a domain can only be accessed by that domain and its subdomains. The standard workaround is to embed an iframe from the foreign domain into the page. That iframe will have access to the cookies of the foreign domain, and its url will be controlled by the local domain, which allows for communication.

A simple solution based on that is to have a table of (domainA sessionid, domainB sessionid) pairs. When a new user arrives to domainA, (new sessionid, NULL) is added to the table; the page shown to him includes an invisible iframe with source = http://domainB/mergeSessions.php?sessionA=1234. mergeSessions.php will then receive sessionA as an URL parameter and sessionB as a cookie, and update the session link table accordingly.

Tgr
+6  A: 

You can use a third domain to identify your customers over all domains.

Use for example a PHP File on http://thirdDomain.com/session.php that is included on all pages on both shops.

Sample:

<script type="text/javascript" src="http://thirdDomain.com/session.php"&gt;&lt;/script&gt;

After your customer switches domains, you can identify him as the same customer using the third domain.

You can assign the session id on both shops to the session id on the third domain to access the cart on both shops. You only need to inform the third domain about your shop sessions (i.e. add them as parameter).

Depending on how flexible you are with your code and templates, you can even use an output from the third domain to define the session id in your shops. This way you can use the same session id on all domains. But normally a session id assignment should be the more secure way.

Using the javascript version you can also output scripts that may add a session id to all outgoing links and forms to the other domain in the current html page. This might be interesting if you can identify your customer as having cookies blocked. You can also use the javascript to inform the parent document about an existing session.

favo
A: 

You could attempt to identify your visitors by IP, browser type, browser version, OS, screen resolution, and whatever else you come up with. That you store in the shared database when someone accesses either site.

If, within a small time window, say < 5 min, requests from that IP with those parameters comes, you can reasonably assume that it's the same user. Again, make sure you use everything you can find find to identify that user and by no means base anything secure on this or you will be subject to hijacking.

Jan Kuboschek
A: 

What about something like this, not sure how good it would be though.

User goes to store1. If user does not have a session cookie, redirect to a special page on store2 asking for the session id and sending the url on store1 to return to. The special page looks at the session cookie and redirects back to the original url on store1 with the session id (like the answer by @symcbean). Then on store1, the session cookie gets set(or created new) and no more redirecting happens. And then the same but oposite if the user is on store2 with no session cookie.

But if the user does not have cookies enabled, I can see an infinite loop happening. Not sure if it would be possible to detect and stop somehow.

But this way would be hacky at best.

Echo
+1  A: 

You can use Flash LSO's for this matter i think. Normally LSO's are stored in their domain specific sandboxes, but if two domain objects allow, they can communicate as stated in the "cross-movie communication" section in http://download.macromedia.com/pub/flash/whitepapers/security.pdf. For general info about LSO's: http://www.adobe.com/products/flashplayer/articles/lso/

Deniz Acay
A: 

1) Obviously, use the same session-store for both domains (files, database, memcached, the usual suspects.
2) If after session_start() the $_SESSION is empty, create an 'all domains' array in the session (do this on every domain, regardless which one it is, ).

$_SESSION['all_domains'] = array(
    'domain1.com'  => true, //<= current domain the customer is on,
    'domain2.com'  => false, //other domain, no cookie for it yet.
    'domain2.com'  => false); //repeat for all domains needed

3) Create a session-setter script on all domains (let's call it 'sesset.php':

 <?php
     if(isset($_GET['sessid']){
          session_id($_GET['sessid']);
          session_start();
          //also, check here for the domains:
          if(!isset($_SESSION['all_domains'])){
              //set the array as before, flag this domain as true.
          } else {
              $_SESSION['all_domains'][$_SERVER['HTTP_HOST']] = true;
              //you might want to set a custom domainname instead of HTTP_HOST, so you won't get doubles from domain with & without www. and so on.
          }
     }
 ?>

4) On every conceivable php HTML page, put this somewhere near the end of the body:

 <?php
     foreach($_SESSION['all_domains'] as $domain => $domainset){
         if(!$domainset){
             echo '<img src="http://'.$domain.'/sesset.php?sessid='.session_id().' width="1" height="1"/>';
         }
     }
 ?>

Not fullproof, but will get almost all users. Ofcourse, one could do it with a redirect cascade instead of 'hidden images', but searchbots (google et al.) very much get confused about it, especially if they don't remember the cookie and are stuck being redirected again & again.

Wrikken
Won't work for Lynx users ;)
Jan Kuboschek
Hence the 'almost' (and possibly also true for screenreaders and other user-agents). Redirecting won't work for people disabling cookies, others won't work without javascript, etc. The actual solution is to actually don't do it cross-domain of course :)
Wrikken
A: 

easyXDM is a framework that allows the user to easily work around the Same Origin Policy. Its built-in RPC feature is very easy to use, and you should be up in running in no-time.

For your case, select one of the domains to be the 'checkout'-domain (A) - this is the domain that will keep the session stored. On the same domain you create a small file with an easyXDM endpoint that is responsible for storing/retrieving the data sent from the other domain (B).

Now, in domain B, you include easyXDM and when storing/retrieving data from the cart, you access the RPC methods instead.

Sean Kinsey
+1  A: 

The schema is quite simple and widely used. By google for it's numerous services for example. You have a whole picture by tracking down HTTP interchange between your browser and various google services to get the idea.

Suppose we have our client authorized for the 1st domain. By getting to the second, we have to:

  1. start a session and store some token in it.
  2. ask browser to request 1st domain somehow and send this token along.
  3. 1st domain will recognize our client and make a connection in the shared database between this token and user id.
  4. By requesting second domain again, we will have it authorized for it's already started session.

The only question remains is how to request 1st domain. It can be a picture, or JS request or entire page redirect. Certain choice is up to you.

Col. Shrapnel
I think this is the best answer so far.
Jan Kuboschek
@Jan Kuboschek: yup, it is.
Sarfraz
A: 

Option 1 Use Iframes:

  • Site 1 has an Iframe of site 2
  • Site 2 has an Iframe of site 1

When a user selects an item from site one, set the iframe value to a dynamic string ie domain2.com/iframe.php?itemid=someitem.

Have domain2 grab the $_GET information with PHP from the iframe and update the user's cookie.

Do the same in the other direction.

Option 2: Javascript includes

You can do something similar with cross-site included JS files generated by PHP to "pull" the contents of the user's cookie to the other site.

Option 3: Curl

Just post the data from one domain to the other, so both have a copy. This is the least secure method since there is no guarantee that the IP address or other identifying data can't be duplicated. Though, you can have some "question" or pass phrase to ensure it is the same person. Possibly by setting an email address?

Option 4: Third-party cookies

I think this one was already mentioned, but you can set the cookies from a third domain, so both sites functionally exactly the same rather than "toggling" back and forth between the two.

Aaron Harun