簡體   English   中英

播放有關cookie和會話的框架安全問題

[英]Play framework security issue regarding cookies and sessions

對於我的應用程序,我正在實現與zentask中所示相同的安全性。

public class Secured extends Authenticator {

@Override
public String getUsername(Context ctx) {
    return ctx.session().get("email");

}

@Override
public Result onUnauthorized(Context ctx) {
    ctx.flash().put("error", "please login to proceed");
    return redirect(routes.Application.index());
}

}

當用戶通過身份驗證時,isuser session().put("email", email) ;

我有兩個問題。 第一:當用戶不使用注銷退出應用程序時,如何使會話無效? 第二個更嚴重的問題是,我使用firefox插件cookies manager+檢查了cookie,並且可以復制一個cookie,然后將其粘貼,這樣就可以不必首先登錄就可以訪問方法,基本上可以竊取會話

Play Framework使用無狀態會話。 服務器端沒有存儲任何狀態,而是所有狀態都存儲在會話cookie中。 為了驗證會話,Play使用密鑰對會話簽名,並在帶有會話cookie的請求到達時驗證簽名。 如果用戶要篡改會話數據,例如,如果他們將會話中的電子郵件地址更改為其他人的電子郵件地址,則簽名將不匹配,因此Play會拒絕會話cookie。

是的,您可以復制cookie並在以后使用。 但是您不能更改Cookie。 這意味着您可以“竊取”的唯一cookie是您自己的,但是從自己身上竊取並不是真正的竊取。 因此,不能,除非利用其他漏洞(例如XSS),否則您無法竊取會話,但是會話令牌也容易受到此攻擊。

默認情況下,Play配置為創建“會話” cookie,即,當您關閉瀏覽器時過期的cookie。 因此,如果用戶退出瀏覽器,瀏覽器將刪除所有會話cookie,並且該用戶將不再登錄。 會話令牌也是如此。

有一個需要注意的注意事項,即會話令牌在服務器上也會過期,因為服務器保持狀態。 沒有狀態的已簽名會話(例如Play中使用的會話)不會。 但是,您可以自己實現過期機制,方法是在創建會話時將時間戳存儲在會話中,並驗證該時間戳不早於getUsername()方法中配置的過期期限。 由於時間戳存儲在已簽名的會話中,因此不更改簽名就無法篡改時間戳,因此這種簡單的機制非常安全。 一個更高級的解決方案可能是實現一個過濾器,該過濾器會在每次請求進入時更新該時間戳記,以使到期時間可以基於上次訪問的時間,而不是基於用戶登錄時的時間。

您的假設是絕對正確的,按照Zentask示例,您不能使服務器上的會話無效。 盡管使用配置文件中的私鑰對會話cookie進行了簽名,但是相同的值會生成相同的簽名的cookie。 正如您已經知道的那樣,如果有人從用戶那里竊取了cookie,則用戶和您(服務器)都無法阻止小偷“登錄”該用戶的帳戶。

現在基本上有兩種選擇:

  1. 將您已經擁有的有關用戶的易失性信息存儲在cookie中,只有您和用戶才能知道並隨時更改。 一個示例是密碼哈希的一部分。 用戶更改密碼后,該信息將不再有效,並且所有舊會話cookie均無效。 此方法的缺點:如果用戶不更改存儲的信息,則cookie可能在很長一段時間內有效,甚至可能永遠有效。
  2. 創建服務器端會話管理。 為此,您必須具有數據庫,鍵值緩存或類似的東西。 在其中存儲會話的隨機生成(加密安全)密鑰,用戶名/ ID和會話將自動失效的日期。 您還可以存儲IP地址,以提高防止cookie竊取的安全性。 然后必須將會話密鑰寫入cookie。 當用戶單擊注銷按鈕時,您使當前會話(或該用戶的所有會話)無效。

僅將用戶標識放在cookie中根本不是安全的。 如您所指出,任何人都可以發明cookie值。

會話:相反,您需要在cookie中放置一個任意(例如隨機)值,然后在服務器上在映射表中查找用戶的身份。 該任意值必須經常更改,因此您的登錄會話通常持續30分鍾。 每次登錄都會提供一個新的任意值,該值稱為會話ID。

無效:在一段時間內沒有任何請求(例如30分鍾)后,通過從查找表(在服務器端)中刪除該條目來使會話無效。 會話ID不在表中的任何請求都將被視為未經身份驗證的請求,然后提示您再次登錄。 用戶忘記注銷都無所謂。

黑客:由於該值是任意的,因此黑客無法提前知道將來的會話ID是什么。 您仍然容易受到會話竊取的攻擊,但是要困難得多:黑客僅在使用會話ID時才必須找到它,然后只能在特定時間內使用它。 您可以采取一些措施來防止這種情況,例如僅允許對特定會話的請求來自特定的IP地址。 您也可以快速循環會話ID,即使是每個請求也可以,但是這有負面影響。 通常,為每個登錄提供唯一的會話ID,尤其是通過HTTPS完成時,足以滿足大多數身份驗證需求。

持久性:如果在任何給定的會話期間(例如30分鍾)內並發用戶數很少,那么您不必將其放入數據庫中。 將其保存在內存中的開銷很低,但缺點是如果您循環服務器,則所有用戶都需要再次登錄。 如果確實將會話ID放在數據庫中,則需要確保服務器啟動時可以清除所有舊會話。

用戶信息:將用戶的電子郵件地址放入cookie中仍然有一個價值,但僅用作“默認”用戶ID身份登錄。 這僅應視為對用戶的便利,而不應視為對用戶進行身份驗證的指示。

  • 我建議使用一個模塊來為您生成會話ID。 在此模塊中,您可以使用諸如createSessionId()之類的方法。 您使用此方法生成會話ID的邏輯。

  • 我將創建會話ID作為(userId + providerId(Facebook / Google- OAuth / UsernamePassword / Any Provider的情況下為Google / Google,如果是OAuth / UsernamePassword / Any Provider的話)+當前時間戳+ UUID)的組合,並在創建此會話ID之后,將使用某種算法對其進行加密。 這將給我會話ID

  • 這樣做的好處是:

    • 盡管生成會話ID會花費一些時間,但是沒有人會理解它。
    • 另一個好處是,您可以隨時在createSessionId()方法中更改創建會話ID的加密邏輯/策略

  • Playframework中會話的另一個問題是會話沒有過期:
    • 為了解決這個問題,只要用戶登錄,我們就可以在會話中存儲時間戳,即在cookie中什么也不能存儲(通過加密可以?
    • 現在,對於每個請求,請檢查會話中的時間戳。 如果時間戳大於30分鍾,則使該會話無效。 如果時間戳不大於30分鍾,則將會話中的時間戳更新為當前時間戳

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM