2011-05-10 43 views
6

Persistent Login Cookie Best Practice,你不應該允許「記住我」令牌競爭條件使用不止一次:持久性「記住我」餅乾

永久Cookie是很好的一個單點登錄。當確認身份驗證時,用於登錄的隨機數無效,並分配一個全新的Cookie。標準會話管理處理會話生命期的憑證,因此新分配的cookie在下次會話之前不會被檢查(在這一點上它也會在使用後失效)。

然後,如何處理用戶在同一時間訪問您網站上的多個URL的競爭情況?我實際上現在有這個問題。

假設兩個請求同時從瀏覽器發送到服務器。這些請求不包含會話cookie,但包含相同的「記住我」cookie。其中一個請求將在另一個之前處理,並且將通過經過驗證的會話cookie和重新生成的「記住我」cookie獲得響應。

第二個請求中的「記住我」令牌現在已失效並且在服務器上生成另一個會話ID。此請求失敗,因爲用戶無法通過身份驗證。

我想出了一些可能的解決方案,但沒有一個看起來很好。我錯過了什麼嗎?

+0

我開始意識到問題是由於http是無狀態的。如果「記住我」令牌沒有立即失效,那麼響應仍會返回不同的會話(並且瀏覽器會覆蓋最後一個會話的舊會話)。 – 2011-05-10 13:22:48

回答

2

老問題,但我沒有找到答案的任何地方。 我有同樣的問題。我的解決方案是將舊標記存儲在數據庫上,並在未找到主標記時將其用作後備。但是我確定舊標記只在短時間內有效,就像標記更改後的幾秒鐘一樣。然後,如果自上一次更新以來已經過去了一段時間,我只會更改該令牌,否則會出現令牌連續多次更改的情況。

1

爲了詳細說明vangoz的答案,我想補充一點,也必須採用某種鎖定機制。這裏考慮這個PHP上下的僞代碼:

if (isFallback($token)) { 
    // Log the user in 
} else { 
    // Usual processing 
    // If token has to be updated, save old token as fallback for a few seconds 
} 

當有else分支,他們可能都結束了併發請求,一個請求會導致更新和其他將導致令牌無效。我解決這個問題的方法是使用一個命名鎖,以$token的名字命名,來包裝else分支。此外,所有併發的請求,但一個將無法獲得鎖,在這種情況下,我們睡一會兒並重試(重試時我們會發現令牌已成爲後備令牌)。

if (isFallback($token)) { 
    // Log the user in 
} else { 
    $couldLock = lock($token); 
    if (!$couldLock) { 
    usleep(10000); 
    // Retry, possibly a recursive call 
    } else { 
    // Usual processing 
    // If token has to be updated, save old token as fallback for a few seconds 
    unlock($token); 
    } 
} 

我希望這些考慮可能有用。