php 安全灵活的跨域会话
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13806701/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Secure and Flexible Cross-Domain Sessions
提问by Brendon Dugan
I am having an issue that I hope you can help with. Let's say I work for a hypothetical company called "Blammo", and we have a hypothetical product called "Log". I am trying to set up a system where someone could log in to logfromblammo.com and order some of our products, and then when they are ready to purchase go to checkout.blammo.com to pay for their order. Eventually I want to allow for Blammo to launch a new hypothetical product with it's own website: rockfromblammo.com, and have that site also able to share a session with checkout.blammo.com so that users can have a single shopping cart across both product websites.
我遇到了一个问题,希望您能帮忙解决。假设我在一家名为“Blammo”的假设公司工作,我们有一个名为“Log”的假设产品。我正在尝试建立一个系统,让人们可以登录 logfromblammo.com 并订购我们的一些产品,然后当他们准备购买时转到 checkout.blammo.com 以支付他们的订单。最终,我想让 Blammo 推出一个新的假设产品,它有自己的网站:rockfromblammo.com,并让该网站也能够与 checkout.blammo.com 共享会话,以便用户可以在这两种产品中拥有一个购物车网站。
Naturally the hypothetical scenario described above is not how my company actually works, but it is a fair example of what I need to do. We have an existing user database, and we have ways to authenticate any of our users on any of our sites, but the goal I have is to allow users to cross seamlessly from one site to another without having to re-authenticate. This would also allow for us to seamlessly transfer data such as a shopping cart to the checkout site.
当然,上面描述的假设场景并不是我公司的实际运作方式,但它是我需要做的一个很好的例子。我们有一个现有的用户数据库,我们有办法在我们的任何站点上对我们的任何用户进行身份验证,但我的目标是允许用户从一个站点无缝切换到另一个站点,而无需重新进行身份验证。这也将使我们能够将购物车等数据无缝传输到结账站点。
I have (briefly) looked at solutions such as OpenID, but I need to be able to integrate whatever solution we have with our existing authentication method, which is not terribly robust. Is there any good way to do this through PHP alone?
我已经(简要地)研究过 OpenID 等解决方案,但我需要能够将我们拥有的任何解决方案与我们现有的身份验证方法集成,这不是非常可靠。有没有什么好的方法可以单独通过 PHP 做到这一点?
回答by Ja?ck
What you could do is create "cross-over" links between the sites to carry the session over.
您可以做的是在站点之间创建“交叉”链接以进行会话。
The simplest way is to pass the session id via the query string; e.g.
最简单的方法是通过查询字符串传递会话ID;例如
http://whateverblammo.com/?sessid=XXYYZZ
Before you start thinking that anyone can trap that information, think about how your cookies are transferred; assuming you're not using SSL, there's not much difference for someone who taps the network.
在您开始认为任何人都可以捕获该信息之前,请考虑您的 cookie 是如何传输的;假设您没有使用 SSL,那么对于使用网络的人来说没有太大区别。
That doesn't mean it's safe; for one, users could accidentally copy/paste the address bar and thus leaking out their session. To limit this exposure, you could immediately redirect to a page without the session id after receiving it.
这并不意味着它是安全的。一方面,用户可能会不小心复制/粘贴地址栏,从而泄露他们的会话。为了限制这种暴露,您可以在收到会话 ID 后立即重定向到没有会话 ID 的页面。
Note that using mcrypt()on the session id won't help much, because it's not the visibility of the value that's the problem; session hiHymaning doesn't care about the underlying value, only its reproducibility of the url.
请注意,mcrypt()在会话 id 上使用不会有太大帮助,因为问题不是值的可见性;会话劫持不关心潜在的价值,只关心它的 url 的可重复性。
You have to make sure the id can be used only once; this can be done by creating a session variable that keeps track of the use count:
您必须确保该 id 只能使用一次;这可以通过创建一个跟踪使用计数的会话变量来完成:
$_SESSION['extids'] = array();
$ext = md5(uniqid(mt_rand(), true)); // just a semi random diddy
$_SESSION['extids'][$ext] = 1;
$link = 'http://othersite/?' . http_build_query('sessid' => session_id() . '-' . $ext);
When received:
收到时:
list($sid, $ext) = explode('-', $_GET['sessid']);
session_id($sid);
session_start();
if (isset($_SESSION['extids'][$ext])) {
// okay, make sure it can't be used again
unset($_SESSION['extids'][$ext]);
}
You need these links every timea boundary is crossed, because the session may have gotten regenerated since the last time.
每次越过边界时,您都需要这些链接,因为会话可能自上次以来已重新生成。
回答by Brenton Alker
It canbe done, but not with simple cookies and it is not trivial. What you are after is a single sign on (SSO) solution, similar to Google's which share's login's across i.google.com, gmail.com, youtube.com etc.
它可以做,但不是简单的饼干,这是不平凡的。您所追求的是单点登录 (SSO) 解决方案,类似于 Google 在 i.google.com、gmail.com、youtube.com 等上共享登录信息。
I have used OpenID to implement this in the past.
我过去曾使用 OpenID 来实现这一点。
The basic idea is to have a single authentication domain (Provider), whenever one of the sites (Consumer) wants to authenticate the user, they redirect them to the authentication domain. If they aren't signed in, they can log in using whatever details you require.
基本思想是有一个单一的身份验证域(提供者),每当站点之一(消费者)想要对用户进行身份验证时,他们将它们重定向到身份验证域。如果他们没有登录,他们可以使用您需要的任何详细信息登录。
If they are already logged in (even from a different target site), they don't need to log in again.
如果他们已经登录(即使是从不同的目标站点),则不需要再次登录。
The user is then sent back to the target site with the addition of a token in the url. This token is used by the target site's server to verify the user is authenticated with the authentication server.
然后通过在 url 中添加令牌将用户发送回目标站点。目标站点的服务器使用此令牌来验证用户是否通过身份验证服务器进行了身份验证。
This is an extremely simple explanation. Doing this is not difficult, doing it securelyis much more so. The details of generating and authenticating the tokens securely is the challenging part. Which is why I suggest building upon a well designed system such as OpenID.
这是一个极其简单的解释。做到这一点并不难,安全地做到这一点更难。安全地生成和验证令牌的细节是具有挑战性的部分。这就是为什么我建议建立在一个设计良好的系统上,比如 OpenID。
回答by K.Alex
In cross domain Ajax, you may find that cookie and, followingly, session are lost for cross domain requests. In case you'll be making ajax calls from you site example.comto your subdomain s2.example.comyou will need to use properties in headers for PHP:
在跨域 Ajax 中,您可能会发现 cookie 以及随后的 session 因跨域请求而丢失。如果您要从您的站点example.com向您的子域s2.example.com进行 ajax 调用,您将需要在 PHP 的标头中使用属性:
header('Access-Control-Allow-Origin: https://example.com');
header('Access-Control-Allow-Credentials: true');
and in JS you going to add
在 JS 中你要添加
xhrFields: { withCredentials: true }
Otherwise cookies are not passed and you can't make use of session on your subdomain.
否则 cookie 不会被传递,您将无法在您的子域上使用会话。
Full JS request to subdomain will be without lost of session:
对子域的完整 JS 请求将不会丢失会话:
$.ajax({
url: "https://s2.example.com/api.php?foo=1&bar=2",
xhrFields: { withCredentials: true },
success:function(e){
jsn=$.parseJSON(e);
if(jsn.status=="success") {
alert('OK!');
} else {
alert('Error!');
}
}
})
回答by Ben Carey
You need to set the session cookie domain like so:
您需要像这样设置会话 cookie 域:
session_set_cookie_params($lifetime,$path,'.site.com')
This will only work if the sites are on the same domain name including TLD(Top Level Domain).
仅当站点位于相同的域名TLD(包括(顶级域))时,这才有效。
See herefor more info
见这里获取更多信息
Alternatively, if you are looking at trying to access sessions cross domains, as in from site1.netto site2.com, then this cannot be done.
或者,如果您正在尝试跨域访问会话,如 from site1.netto site2.com,则无法完成此操作。
回答by troelskn
If it's OK for your site to rely on Javascript to function, you could presumably do something like the following:
如果您的网站可以依赖 Javascript 来运行,那么您大概可以执行以下操作:
Say you have a session on blammo.com and you want to access it from rockblammo.com. On the rockblammo.com page you could load a <script>from blammo.com/get-session.js, this will (from the server side) return the session-id. Once that returns, you insert a new <script>tag in the page, pointing to rockblammo.com/set-session.js?sessionId=XXX, where XXX is the session-id you just got from blammo.com. Now, on the server side of rockblammo.com, the session cookie is updated and set to this session-id. Going forward, the two pages will now share the same session-id, and assuming they have access to the same session store on the backend, they would be in sync.
假设您在 blammo.com 上有一个会话,并且您想从 rockblammo.com 访问它。在rockblammo.com 页面上,您可以加载一个<script>from blammo.com/get-session.js,这将(从服务器端)返回会话ID。返回后,您<script>在页面中插入一个新标签,指向rockblammo.com/set-session.js?sessionId=XXX,其中 XXX 是您刚从 blammo.com 获得的会话 ID。现在,在rockblammo.com 的服务器端,会话cookie 被更新并设置为这个会话ID。展望未来,这两个页面现在将共享相同的会话 ID,并且假设它们可以访问后端的相同会话存储,它们将保持同步。
E.g. the output from blammo.com/get-session.jswould be:
例如,输出blammo.com/get-session.js将是:
var sessionId = "XXX";
var s = document.createElement("script");
s.src = "/set-session.js?sessionId=" + escape(sessionId);
document.body.appendChild(s);
The output from rockblammo.com/set-session.jswould be blank, but would include a http header, such as:
来自的输出rockblammo.com/set-session.js将为空白,但会包含一个 http 标头,例如:
Set-Cookie: sessionId=XXX
If you prefer not to rely on Javascript, you could probably do the same by redirecting forth and back between the two sites and passing the sessionId in a query-string parameter (GET param).
如果您不想依赖 Javascript,您可以通过在两个站点之间来回重定向并在查询字符串参数 (GET param) 中传递 sessionId 来做同样的事情。

