【问题标题】:Cross domains sessions - shared shopping cart cross domains跨域会话 - 跨域共享购物车
【发布时间】:2011-02-26 17:24:59
【问题描述】:

我们正在解决 eshop (php, mysql) 的问题。客户希望通过共享购物车在两个域上拥有相同的 eshop。在商店客户可以在没有用户帐户的情况下购物(无法登录)。还有一个问题,如何使共享购物车跨域。

购物车中的数据存储在会话中,我们也将其存储在数据库中。但是我们无法解决跨域传输数据的问题。识别未登录的用户并不是万无一失的 (research)。

示例,它应该如何工作

客户前往 domainOne 并将一些东西添加到购物车。然后他去 domainTwo (通过链接,但是输入域地址)并将其他一些东西添加到购物车中。在购物车中,他有来自两个域的东西(刷新页面后)。

你有什么想法,如何解决这个问题?

什么没用:

  • 由于客户要求,无法进行重定向
  • cookie 与域相关
  • 其他域的 set_cookie 无效
  • 最简单的方法是只保留 sessionid(存储在 cookie 中),但我们不知道如何整体证明未登录的用户。
  • 除了cookies之外,还有没有其他地方可以在客户端存储数据? (可能不会)
  • 我们不能使用通过 url 中的参数发送 sessionid(如果用户点击链接到其他域)或解析标头引用,bcs 我们不知道用户如何实现其他域。

如果你不明白我的意思,请向我提问。如果您认为在两个域上使用共享(公共)购物车进行 eshop 是个坏主意,请不要告诉我,我们知道。

感谢您的每一个回答。

【问题讨论】:

  • 如果没有某种身份验证/登录机制,这个问题就无法得到充分解决。因此,请尝试让客户相信登录是必要的,并解释其优点(即提出有针对性的建议)和缺点(即可能会让一些潜在客户失望)。我敢肯定,最终,如果这真的是必要的壮举,客户会很乐意采用登录机制。

标签: php session cookies cross-domain client-side


【解决方案1】:

您可以使用第三个域来识别所有域中的客户。

例如使用http://thirdDomain.com/session.php 上的 PHP 文件,该文件包含在两家商店的所有页面中。

示例:

<script type="text/javascript" src="http://thirdDomain.com/session.php"></script>

您的客户切换域后,您可以使用第三个域将他识别为同一客户。

您可以将两个商店的会话 ID 分配给第三个域上的会话 ID,以访问两个商店的购物车。您只需要通知第三个域您的商店会话(即添加它们作为参数)。

根据您对代码和模板的灵活程度,您甚至可以使用来自第三个域的输出来定义您商店中的会话 ID。这样您就可以在所有域上使用相同的会话 ID。 但通常会话 ID 分配应该是更安全的方式。

使用 javascript 版本,您还可以输出脚本,这些脚本可能会将会话 ID 添加到当前 html 页面中的其他域的所有传出链接和表单。如果您可以将您的客户识别为阻止了 cookie,这可能会很有趣。 您还可以使用 javascript 通知父文档有关现有会话的信息。

【讨论】:

  • 这个答案可以稍微修饰一下 - session.php javascript文件会提供什么?一组函数 ? JSON 对象??
  • 我知道这是一个旧答案,但是如何阻止攻击者将 session.php 链接添加到他们服务器上的页面并窃取会话?我假设引荐来源标头不可信。
  • @ClearCarbon 你可以添加 CSRF 令牌吗?
  • 会话只能在 session.php 脚本中访问,而不能在您在其他域中编写的 php 脚本中访问,对吗?还是在 session.php 中添加代码来共享两个上下文之间的会话?
【解决方案2】:

这一直被问到。

搜索 SSO。

您需要跨域传递 URL(或 POST)中的会话 ID,然后:

1) 检查目标域上不存在会话

2) 使用发送的会话 ID 重新绑定会话

例如

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;
}

这也意味着您需要添加 '?passed_id=' 。 urlencode(session_id()) 指向任何指向其他域的 URL。

C.

【讨论】:

  • 我们知道这种方式,但我们不能保证每个url都添加sessid。那么情况如何:客户打开了两个浏览器选项卡并同时将东西添加到购物车?所以 - 我们不能在 url 中保留 sessid。
  • 那么你就不能有跨域购物车了。故事结束。
  • 听起来像是会话固定的邀请。
  • 仍然很危险。攻击者可以打开一个会话,诱骗某人进入该会话,然后自己使用该会话,例如在最后一秒更改订单地址。从 GET 参数设置会话 id 不一定是漏洞,但很容易出错。 (尽管其他跨域篮子方案也可能如此。)
  • 无论如何,您需要在 URL 中显示会话 id 才能使跨域篮子工作,这是不正确的;有很多方法可以解决这个问题。仅举一个例子:每当您开始一个新会话时,将图像放入页脚,将另一个域中的脚本设置为其源,并将会话 ID 作为参数传递。然后该脚本在另一个域上使用相同的 sessionid 启动一个会话,并返回一个不可见的像素。
【解决方案3】:

该模式非常简单且被广泛使用。例如,谷歌提供了众多服务。通过跟踪浏览器和各种谷歌服务之间的 HTTP 交换来了解这个想法,您可以了解全局。

假设我们的客户已获得第一个域的授权。通过达到第二个,我们必须:

  1. 启动会话并在其中存储一些令牌。
  2. 要求浏览器以某种方式请求第一个域并发送此令牌。
  3. 第一个域将识别我们的客户端并在共享数据库中建立此令牌和用户 ID 之间的连接。
  4. 通过再次请求第二个域,我们将对其已启动的会话进行授权。

剩下的唯一问题是如何申请第一个域。可以是图片,也可以是 JS 请求,也可以是整页重定向。某些选择取决于您。

【讨论】:

  • 我认为这是迄今为止最好的答案。
【解决方案4】:

我认为你可以使用 Flash LSO 来解决这个问题。通常 LSO 存储在其特定于域的沙箱中,但如果两个域对象允许,它们可以按照http://download.macromedia.com/pub/flash/whitepapers/security.pdf 中的“跨电影通信”部分所述进行通信。 有关 LSO 的一般信息: http://www.adobe.com/products/flashplayer/articles/lso/

【讨论】:

    【解决方案5】:

    单点登录。

    CartA 具有 iframe 1)检查用户是否“活跃”(有会话)2)创建匿名会话 CartB 具有执行 1) 或 2) 的 iframe

    从 SSO 域(您可以拥有的任何域)加载 iframe

    SSO 解决方案:构建您的或使用其他解决方案 - 例如 simplesamlphp 或其他...

    而且应该不需要使用 URI 传递会话/参数...

    【讨论】:

      【解决方案6】:

      您可以将数据存储在 cookie 以外的其他位置(例如 Flash cookie,localStorage),但都使用同源策略,这是网络的标准安全模型:域存储的数据只能由该域访问及其子域。标准的解决方法是将外部域中的 iframe 嵌入到页面中。该 iframe 将可以访问外部域的 cookie,其 url 将由本地域控制,从而允许通信。

      基于此的简单解决方案是有一个 (domainA sessionid, domainB sessionid) 对的表。当一个新用户到达 domainA 时,(new sessionid, NULL) 被添加到表中;显示给他的页面包含一个不可见的 iframe,source = http://domainB/mergeSessions.php?sessionA=1234。然后,mergeSessions.php 将接收 sessionA 作为 URL 参数和 sessionB 作为 cookie,并相应地更新会话链接表。

      【讨论】:

        【解决方案7】:

        您可以尝试通过 IP、浏览器类型、浏览器版本、操作系统、屏幕分辨率以及您想出的任何其他内容来识别您的访问者。当有人访问任一站点时,您存储在共享数据库中。

        如果在一个小的时间窗口内,比如 合理地假设它是同一个用户。同样,请确保您使用可以找到的所有内容来识别该用户,并且绝不要以此为基础,否则您将受到劫持。

        【讨论】:

          【解决方案8】:

          这样的东西怎么样,但不知道它有多好。

          用户前往 store1。如果用户没有会话 cookie,则重定向到 store2 上的特殊页面,询问会话 id 并发送 store1 上的 url 以返回。特殊页面查看会话 cookie 并使用会话 id 重定向回 store1 上的原始 url(如 @symcbean 的答案)。然后在 store1 上,会话 cookie 被设置(或创建新的)并且不再发生重定向。如果用户在 store2 上没有会话 cookie,则相同但相反。

          但如果用户没有启用 cookie,我会看到发生了无限循环。不确定是否有可能以某种方式检测并停止。

          但这种方式充其量只是 hacky。

          【讨论】:

            【解决方案9】:

            1) 显然,对两个域(文件、数据库、memcached、通常的嫌疑人)使用相同的会话存储。
            2) 如果在 session_start() 之后 $_SESSION 为空,则在会话中创建一个“所有域”数组(在每个域上执行此操作,无论它是哪个域)。

            $_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) 在所有域上创建会话设置器脚本(我们称之为“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) 在每个可能的 php HTML 页面上,将其放在正文末尾附近的某处:

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

            不是完全证明,但会吸引几乎所有用户。当然,可以使用重定向级联而不是“隐藏图像”来做到这一点,但是搜索机器人(谷歌等)对此非常困惑,特别是如果他们不记得 cookie 并且被一次又一次地重定向。

            【讨论】:

            • 因此是“几乎”(对于屏幕阅读器和其他用户代理也可能如此)。重定向不适用于禁用 cookie 的人,其他人在没有 javascript 的情况下无法工作等。实际的解决方案当然是实际上不要跨域:)
            【解决方案10】:

            easyXDM 是一个允许用户轻松解决同源策略的框架。 它内置的 RPC 功能非常易于使用,您应该可以立即开始运行。

            对于您的情况,请选择一个域作为“结帐”域 (A) - 这是将保存会话的域。在同一个域上,您创建一个带有 easyXDM 端点的小文件,该端点负责存储/检索从其他域 (B) 发送的数据。

            现在,在域 B 中,您包含 easyXDM,并且在从购物车存储/检索数据时,您访问的是 RPC 方法。

            【讨论】:

              【解决方案11】:

              选项 1 使用 iframe:

              • 站点 1 具有站点 2 的 iframe
              • 站点 2 具有站点 1 的 iframe

              当用户从站点一中选择项目时,将 iframe 值设置为动态字符串,即 domain2.com/iframe.php?itemid=someitem。

              让 domain2 使用 PHP 从 iframe 中获取 $_GET 信息并更新用户的 cookie。

              在另一个方向做同样的事情。

              选项 2:Javascript 包括

              您可以对 PHP 生成的跨站点包含的 JS 文件执行类似的操作,以将用户 cookie 的内容“拉”到其他站点。

              选项 3:卷曲

              只需将数据从一个域发布到另一个域,因此两者都有一个副本。这是最不安全的方法,因为无法保证 IP 地址或其他识别数据不会被复制。不过,您可以有一些“问题”或密码短语来确保它是同一个人。可能通过设置电子邮件地址?

              选项 4:第三方 cookie

              我认为已经提到过这个,但是您可以从第三个域设置 cookie,因此两个站点的功能完全相同,而不是在两者之间“切换”。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-08-01
                • 2012-10-05
                • 2021-01-25
                • 2011-06-11
                • 1970-01-01
                相关资源
                最近更新 更多