2011-11-17 285 views
25

我工作的產品受到潛在客戶的嚴格安全審覈,他們對於Tomcat在認證發生之前設置JSESSIONID Cookie感到不安。也就是說,Tomcat在我們的無狀態登錄頁面加載時,但在登錄之前設置此cookie。如何在登錄後刷新JSESSIONID cookie

他們建議以下任一操作:

  1. 問題的新JSESSIONID的cookie登錄後
  2. 防止在登錄頁面首先被設置JSESSIONID的cookie(即驗證已經發生之前)

我一直在鑽研與本網站相關的所有JSESSIONID,並且找不到簡單的答案。我只是希望有一些想法。對於每一個我最好的解決方案是:

  1. 登錄之後,克隆複製的所有屬性,舊的會話無效,創建一個新的,複製的值,它與請求關聯的會話(減去ID) ,並希望這有效。
  2. 在最初加載登錄頁面之前,在鏈的最末端創建一個servlet過濾掉JSESSIONID cookie。然後希望登錄請求在沒有JSESSIONID集的情況下運行。

我必須睡一會兒,但早上會嘗試這些。從人那裏獲得一些比我更聰明的反饋或更好的建議將會非常棒 - 像你一樣!

無論如何,我會在這裏發佈我的結果,因爲它好像很多其他人一直想要做類似的事情。

回答

34

你不會刷新後,但只是之前。當執行登錄操作首先做到:

HttpSession session = request.getSession(false); 
if (session!=null && !session.isNew()) { 
    session.invalidate(); 
} 

然後做:

HttpSession session = request.getSession(true); // create the session 
// do the login (store the user in the session, or whatever) 

FYI你用這一招解決是http://www.owasp.org/index.php/Session_Fixation

最後你可以禁用自動會話創建,只有創建當你真的需要它時。如果你使用JSP,你可以這樣做:

<%@page contentType="text/html" 
     pageEncoding="UTF-8" 
     session="false"%> 
+0

有趣的東西。我正在使用Wicket 1.3,而且我似乎無法找到設置'session = false'的方法(視圖方不是基於JSP的)。我現在要嘗試getSession(false)想法...謝謝! –

+0

在登錄之前使會話失效導致Wicket混亂(只是重定向到登錄頁面)。仍然搞這個...... –

+1

@RichardsonHeights:看看https://issues.apache.org/jira/browse/WICKET-1767。它似乎記錄和解決。 – cherouvim

1

問題是JSESSIONID在瀏覽器中可見,或者它根本在cookie中設置?我假設你的情況是後者。

1.issue一個新的登錄

這之後JSESSIONID cookie是默認的Tomcat行爲如果從HTTP在登錄時切換爲HTTPS。舊的被丟棄,併產生一個新的。

如果您的登錄本身是通過HTTP,我想這是審計人員的另一個安全問題;)

或者是所有的頁面通過https?

+0

問題是,JSESSIONID cookie在瀏覽器中設置,並在Firefox cookie查看器中可見(例如)。正如Cherouvim指出的那樣,這是「會話固定」安全漏洞。 有趣的HTTP/HTTPS切換...該應用程序只能運行在https上,不過。 –

1

我發現的兩件事可能對別人有幫助。

  1. 如果您使用的是Apache Wicket,那麼在版本1.4之後有一個解決方案。我的應用程序仍然在1.3,所以我沒有意識到,但我可以很容易地在我自己的WebSession類中將它移回端口。 Wicket 1.4爲WebSession添加了一個replaceSession()方法,該方法效果很好。你可以在認證後立即調用它,你會得到一個新的JSESSIONID。它基本上爲我解決了這個問題。更多的信息在這裏:https://issues.apache.org/jira/browse/WICKET-1767

  2. 在5.5.29版本之後有一個Apache Tomcat閥可以添加到context.xml中。它將在驗證後處理髮布新的JSESSIONID。更多信息請點擊這裏:https://issues.apache.org/bugzilla/show_bug.cgi?id=45255。閥門的入口應該是這樣的:<Valve className="org.apache.catalina.authenticator.FormAuthenticator" changeSessionIdOnAuthentication="true"/>

4

我不能@ cherouvim的回答上面的評論,因爲我沒有足夠的積分。新會話ID應該在用戶成功登錄後設置,以避免會話固定。我會試着解釋我的推理。

會話固定實際上意味着攻擊者以某種方式誘騙用戶使用攻擊者已知的值。爲了簡單起見,讓我們假設攻擊者走到用戶的桌面,使用Firebug並編輯用戶的cookie。現在,當用戶登錄時,他/她將用攻擊者控制的cookie登錄。由於攻擊者也知道這個值,他/她將刷新瀏覽器,映射到該會話ID(受害者的資源)的資源將被提供給他們。這是會議固定。正確?

現在我們假設我們在受害者用戶登錄之前運行了session.invalidate。讓我們假設cookie最初有一個abc值。運行session.invalidate abc值將從服務器的會話中清除。

現在出現我不同意的部分。您建議在用戶實際登錄之前生成一個新會話(輸入用戶名和密碼並單擊提交)。這無疑會導致一個新的cookie生成,但它會在用戶的瀏覽器登錄之前。因此,如果攻擊者可以再次編輯「prelogin」cookie,攻擊仍然存在,因爲即使用戶登錄後也會使用相同的cookie。

我認爲這是正確的流程。

  • 用戶做一個GET /login.html
  • 返回登錄頁面與任何cookie是目前存在於瀏覽器
  • 用戶輸入憑據,並點擊提交
  • 應用驗證憑據
  • 在發現憑據是正確的。 session.invalidate()運行..銷燬舊的cookie。
  • 現在可以生成使用request.getSession(真)

這意味着什麼,是,即使攻擊者設法誘騙您登錄之前,使用一個控制值,你就是新的cookie仍然保護..如果應用程序強制更改您登錄後的值。

這裏是關於這個問題一個很好的博客 - https://blog.whitehatsec.com/tag/session-fixation/

3

我按照下面的方式來重新從舊會話的新的會話。希望你能從中受益。

private void regenerateSession(HttpServletRequest request) { 

    HttpSession oldSession = request.getSession(); 

    Enumeration attrNames = oldSession.getAttributeNames(); 
    Properties props = new Properties(); 

    if (attrNames != null) { 
     while (attrNames.hasMoreElements()) { 
      String key = (String) attrNames.nextElement(); 
      props.put(key, oldSession.getAttribute(key)); 
     } 

     //Invalidating previous session 
     oldSession.invalidate(); 
     //Generate new session 
     HttpSession newSession = request.getSession(true); 
     attrNames = props.keys(); 

     while (attrNames.hasMoreElements()) { 
      String key = (String) attrNames.nextElement(); 
      newSession.setAttribute(key, props.get(key)); 
     } 
    } 
-1
session=request.getSession(true); 
Enumeration keys = session.getAttributeNames();  
HashMap<String,Object> hm=new HashMap<String,Object>(); 
while (keys.hasMoreElements()) 
{ 
    String key = (String)keys.nextElement(); 
    hm.put(key,session.getValue(key)); 
    session.removeAttribute(key);  
} 
session.invalidate(); 
session=request.getSession(true); 
for(Map.Entry m:hm.entrySet()) 
{ 
    session.setAttribute((String)m.getKey(),m.getValue()); 
    hm.remove(m); 
} 
0

使用的彈簧,你應該使用SessionFixationProtectionStrategy

<property name="sessionAuthenticationStrategy" ref="sas"/> 
... 
<bean id="sas" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy"/> 

在視察source code,你會看到,這類似於harsha89的方法:將

  1. 創建一個新的會話舊的會話的
  2. 轉院屬性。
0

如果您使用的是Tomcat,並希望在全球範圍內應用該到所有的servlet它們使用Tomcat的身份驗證機制,你可以寫一個閥門,迫使這種行爲,如本sample code.

0

如果您正在使用像jboss 4那樣的老版本的jboss,然後在session.invalidate()調用之後簡單地調用request.getSession(true)將不會更改會話標識。

如果您不想使用閥門並想在操作類中更改會話標識,則可以使用反射來歸檔相同的標識,因爲CatalinaRequest將不會直接在您的操作類中提供。

示例代碼

private HttpSession changeSessionId(HttpServletRequest request) 
{ 
    HttpSession oldSession = request.getSession(false); 
    HttpSession newSession = null; 

    try 
    { 
     //get all cookies from request 
     Cookie[] cookies = request.getCookies(); 

     //Get all attribute from old session 
     Enumeration<Object> attrNames = oldSession.getAttributeNames(); 

     Properties attributFromOldSession = new Properties(); 

     while (attrNames.hasMoreElements()) 
     { 
      String key = (String)attrNames.nextElement(); 
      attributFromOldSession.put(key, oldSession.getAttribute(key)); 
     } 

     //Actual logic to change session id 

     Field catalinaRequestField; 

     //Getting actual catalina request using reflection 
     catalinaRequestField = request.getClass().getDeclaredField("request"); 
     catalinaRequestField.setAccessible(true); // grant access to (protected) field 
     Request realRequest = (Request)catalinaRequestField.get(request); 

     //Invalidating actual request 
     realRequest.getSession(true).invalidate(); 
     realRequest.setRequestedSessionId(null); 
     realRequest.clearCookies(); 

     //setting new session Id 
     realRequest.setRequestedSessionId(realRequest.getSessionInternal(true).getId()); 

     //Put back the cookies 
     for (Cookie cookie : cookies) 
     { 

      if (!"JSESSIONID".equals(cookie.getName())) 
      { 
       realRequest.addCookie(cookie); 
      } 
     } 

     // put attribute from old session 
     attrNames = attributFromOldSession.keys(); 

     while (attrNames.hasMoreElements()) 
     { 
      String key = (String)attrNames.nextElement(); 
      newSession.setAttribute(key, attributFromOldSession.get(key)); 
     } 
    } 
    catch (Exception e) 
    { 
     e.printStackTrace(); 
    } 
    return newSession; 

} 
0

HttpServletRequest.changeSessionId()可以使用在任何時間點來改變會話ID。