2012-12-10 55 views
6

我有一個問題,我希望你能幫助。假設我爲一家名爲「Blammo」的假設公司工作,我們有一個假設的產品叫做「Log」。我正在嘗試建立一個系統,讓有人可以登錄到logfromblammo.com並訂購我們的一些產品,然後當他們準備購買時,請去checkout.blammo.com支付訂單費用。最終,我想允許Blammo推出一個新的假想產品,它有自己的網站:rockfromblammo.com,並且該網站還可以與checkout.blammo.com共享一個會話,以便用戶可以在兩個產品中都擁有一個購物車網站。安全和靈活的跨域會話

上面描述的假設場景當然不是我公司實際工作的方式,但它是我需要做的一個合適的例子。我們有一個現有的用戶數據庫,並且我們有辦法在我們的任何網站上對我們的任何用戶進行身份驗證,但我的目標是允許用戶無需重新進行身份驗證即可從一個站點無縫地跨接到另一個站點。這也可以讓我們無縫地將購物車等數據傳輸到結帳網站。我有(簡要地)看過OpenID這樣的解決方案,但是我需要能夠將我們擁有的任何解決方案與我們現有的身份驗證方法集成在一起,這種解決方案並不十分健壯。單獨使用PHP有沒有什麼好的方法?

+0

所以基本上你的網站有多個二級域名,而不是'product.site.com'樣? –

+2

我認爲你最好的解決方案是讓rockfromblammo.com重定向到rockfrom.blammo.com - 安全是這樣的事情中的一個大問題,並且允許將購物車訪問到兩個不同的域,從而打開一些第三方的風險弄清楚如何做同樣的事情。 – Blazemonger

+0

@Blazemonger它不僅僅是一個安全風險,它不能跨域進行。它只能做跨子域! –

回答

7

您可以做的是在站點之間創建「交叉」鏈接來進行會話。

最簡單的方法是通過查詢字符串傳遞會話ID;例如

http://whateverblammo.com/?sessid=XXYYZZ 

在您開始思考任何人都可以捕獲該信息之前,請考慮您的cookie是如何傳輸的;假設你沒有使用SSL,那麼點擊網絡的人沒有太大的區別。

這並不意味着它是安全的;舉例來說,用戶可能會意外地複製/粘貼地址欄,從而泄漏他們的會話。爲了限制這種風險,您可以在收到後立即重定向到沒有會話ID的頁面。

請注意,在會話ID上使用mcrypt()不會有太大幫助,因爲這不是問題的可見性;會話劫持並不關心底層的價值,只關注網址的可重複性。

您必須確保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); 

當收到:

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

你需要每次這些鏈接一個越過邊界,因爲會話自上次以來可能已經重新生成。

1

您需要設置會話cookie域,像這樣:

session_set_cookie_params($lifetime,$path,'.site.com') 

如果網站在相同的域名,包括TLD(頂級域名)這隻會工作。

更多信息,請參見here

或者,如果你正在尋找在試圖訪問會話跨域,如從site1.netsite2.com,那麼這個不能做。

3

可以可以完成,但不是簡單的cookies,也不是微不足道的。你所追求的是單點登錄(SSO)解決方案,類似於谷歌在i.google.com,gmail.com,youtube.com等網站上的登錄信息。

我以前使用過OpenID來實現此功能。

基本思想是擁有一個認證域(Provider),只要其中一個站點(消費者)想要對用戶進行身份驗證,他們就會將其重定向到身份驗證域。如果他們沒有登錄,他們可以使用您需要的任何詳細信息登錄。

如果他們已經登錄(即使是從不同的目標站點),他們也不需要再次登錄。

然後用戶被髮送回目標站點並在url中添加一個標記。目標站點的服務器使用此令牌來驗證用戶是否已通過身份驗證服務器的身份驗證。

這是一個非常簡單的解釋。這樣做並不困難,安全地做更是如此。安全地生成和驗證令牌的細節是具有挑戰性的部分。這就是爲什麼我建議建立在一個設計良好的系統上,比如OpenID。

0

如果它是確定爲您的網站依賴於JavaScript的功能,你大概可以做類似如下:

說你有blammo.com一個會議,你想從rockblammo.com訪問它。在rockblammo.com頁面上,您可以從blammo.com/get-session.js加載<script>,這將(從服務器端)返回會話ID。一旦返回,您將在頁面中插入一個新的<script>標記,指向rockblammo.com/set-session.js?sessionId=XXX,其中XXX是您剛剛從blammo.com獲得的會話標識。現在,在rockblammo.com的服務器端,會話cookie被更新並設置爲此會話ID。展望未來,這兩個頁面現在將共享相同的會話ID,並假設他們可以訪問後端上的同一個會話存儲,它們將同步。

E.g.從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); 

rockblammo.com/set-session.js輸出將是空白的,但將包括HTTP頭,如:

Set-Cookie: sessionId=XXX 

如果你不喜歡依賴於JavaScript,你可以可能通過在兩個站點之間重定向並在查詢字符串參數(GET參數)中傳遞sessionId來做同樣的事情。

0

在跨域Ajax中,您可能會發現cookie和以下會話因跨域請求而丟失。

header('Access-Control-Allow-Origin: https://example.com'); 
header('Access-Control-Allow-Credentials: true'); 

和JS你打算:萬一你會從你的網站example.com到您的子s2.example.com你需要在頭使用性質爲PHP來進行Ajax調用添加

xhrFields: { withCredentials: true } 

否則cookie不會通過,您不能在您的子域中使用會話。

完全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!'); 
     } 
    } 
})