保護你的會話令牌
保護你的會話令牌
通常我們會采取以下的措施來保護會話。
1.采用強算法生成Session ID
正如我們前面用Web Scrab
分析的那樣,會話ID
必須具有隨機性和不可預測性。一般來說,會話ID
的長度至少為128
位。下面我們就拿常見的應用服務器Tomcat
來說明如何配置會話ID
的長度和生成算法。
首先我們找到{TOMCAT_HOME}\conf\context.xml,然后加入下面一段設置
<Manager sessionIdLength="20" ➊
secureRandomAlgorithm="SHA1PRNG" ➋
secureRandomClass="java.security.SecureRandom" ➌
/>
➊ 定義會話ID 的長度,如果我們這里不聲明的話,默認是16字節。可能有讀者會納悶,怎么平時我看到的會話ID都是很長的呀?我們就拿這里的20個字節來講吧,我們在瀏覽器發送請求時會發現這樣的會話ID:
JSESSIONID=90503B6BE403D4AB6164A311E167CF1F6F3F2BD0
仔細看會發現ID的長度為40,因為這里顯示的是十六進制,每兩個字符代表一個字節。
➋ 定義隨機數算法,默認的是SHA1PRNG,你也可以換成自己的算法。
➌ 定義隨機數類,默認的是java.security.SecureRandom,我們也可以繼承這個類來實現自己的算法。
有一點要注意,就是我們在實現自己的隨機數算法時,一定要保證生成的Session ID不能有重復,這里我們參考一下Tomcat實現的機制。
/**
* Generate and return a new session identifier.
*/
protected () {StringgenerateSessionId
String result = null;
do {
if (result != null) {
duplicates++;
}
result = sessionIdGenerator.generateSessionId();
} while (sessions.containsKey(result));
return result;
}
由此可見,Tomcat是不會產生兩個相同的會話ID的。
2.軟硬兼施,會話過期
會話過期是應用程序的一項重要的安全控制,它定義了用戶在多長時間段內不用重新登錄而仍然維持一個登錄狀態。一般來說,有兩種會話過期——軟會話過期(Soft Session Timeout)和硬會話過期(Hard Session Timeout)。
軟會話過期,它指的是用戶在一定的時間內與應用系統沒有交互,則會話過期。舉一個簡單的例子就是,一個用戶登錄了一個應用系統,他臨時離開了計算機40分鐘,而應用系統設置的會話過期時間為30分鐘,這時候用戶回到計算機前再做任何操作,系統都會重定向為登錄頁面讓用戶重新輸入用戶名和密碼。
那么,軟會話過期有什么用呢?我們知道在CSRF***中一個最基本的假設就是合法用戶處在一個登錄狀態中,如果我們設置了一個合理的且較低的會話過期時間,就提高了實施CSRF***的難度,從而保護了系統。
通常有3種辦法來設定軟會話過期,其級別由高到低依次為:Tomcat級別> Web應用級別>Servlet運行時context級別,這時候低級別的設定會覆蓋高級別的設定。
a.Tomcat級別的設定。
若你需要設定30分鐘的會話過期,你可以在{TOMCAT_HOME}\conf\web.xml中進行設定如下:
<session-config>
<session-timeout>30</session-timeout><!-- set in minutes -->
</session-config>
b.Web應用級別的設定。
若你需要設定15分鐘的會話過期,你可以在{TOMCAT_HOME}\webapps\ {APP_NAME}\WEB-INF\web.xml中這樣進行設定:
<session-config>
<session-timeout>15</session-timeout><!-- set in minutes -->
</session-config>
c.在程序代碼中進行設定。
若你需要在程序中設定5分鐘的會話過期,你可以用下面一行代碼來實現:
httpSession.setMaxInactiveInterval(5*60); // set in seconds
如果我們按照上面的步驟進行了會話過期設置,那么最后真正起作用的是在程序中進行設定的5分鐘。
再看什么是硬會話過期。它指的是用戶登錄到系統中經過一定的時間后,不管用戶做什么,該會話都會過期。大家都知道網絡游戲防沉迷系統吧?如果未成年人的累計在線時間已滿5小時,則累計在線時間清零,這個與我們這里說的硬會話過期很相似,只不過我們這里不是在線時間清零,而是強制用戶退出并重新登錄。
那么硬會話過期有什么用呢?它主要是用來防止永久的對一個賬號劫持。比如說一個***者通過XSS得到了受害者的session,并用它冒充受害者進行登錄,如果我們設定了硬會話過期,則經過了一段時間之后,系統會強制用戶重新進行認證。
沒有專門的API或者配置來設定硬會話過期,但我們可以通過在web filter中寫自己的代碼來實現這個功能。基本思路如下:對每個用戶登錄成功后記錄下此時的時間,并且把這個時間與他們的Session ID綁定起來,如果用同一個Session ID發送的請求的時間減去這個Session ID剛登錄成功的時間大于了我們設定的會話過期時間,則使這個會話無效,并重定向到登錄頁面。
3.保護你的Cookie
Cookie有兩個很重要的屬性:secure和HttpOnly,設置好這兩個屬性對于保護你的Cookie至關重要。
首先說secure屬性。聲明了它,則說明當前這個Cookie只會在HTTPS的鏈接中進行傳遞,這樣就可以使得***者無法很容易地通過分析網絡流量來獲得會話ID,從而有效地防治了中間人***(Man-in-the-Middle)。
HttpOnly這個屬性我們在XSS這一章已經介紹過,它不允許一些腳本(如JavaScript等)直接操作document.cookie這個DOM對象,這個屬性對于阻止通過XSS竊取會話ID是必需的。
一個好消息是,Tomcat 7支持了Servlet 3.0,所以我們可以在web.xml設定上面的兩個屬性。
<session-config>
<cookie-config>
<secure>true</secure>
</cookie-config>
<cookie-config>
<http-only>true</http-only>
</cookie-config>
</session-config>
需要注意的是Tomcat 6以前的版本不支持,Tomcat 6支持的是Servlet 2.5。
4.提供logout功能
上面介紹的是系統自動按照設定的時間使會話過期,一個好的應用程序應該提供一個功能,即用戶可以手動地使當前會話過期,這就是我們在幾乎所有網站上都看到的logout按鈕。那么一般的logout需要完成哪些功能呢?讓我們看看ESAPI中是如何實現logout功能的吧。
Class: org.owasp.esapi.reference.DefaultUser
public void logout() {
ESAPI.httpUtilities().killCookie( ESAPI.currentRequest(),
ESAPI.currentResponse(),
HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME );➊
HttpSession session = ESAPI.currentRequest().getSession(false);
if (session != null) {
removeSession(session);
session.invalidate();➋
}
ESAPI.httpUtilities().killCookie(ESAPI.currentRequest(),
ESAPI.currentResponse(),
"JSESSIONID");➌
loggedIn = false;
logger.info(Logger.SECURITY_SUCCESS, "Logout successful" );
ESAPI.authenticator().setCurrentUser(User.ANONYMOUS);
}
killCookie的實現代碼如下:
public void killCookie(HttpServletRequest request, HttpServletResponse response, String name) {
String path = "//";
String domain="";
Cookie cookie = getFirstCookie(request, name);
if ( cookie != null ) {
path = cookie.getPath();
domain = cookie.getDomain();
}
Cookie deleter = new Cookie( name, "deleted" );
deleter.setMaxAge( 0 );➍
if ( domain != null ) deleter.setDomain( domain );
if ( path != null ) deleter.setPath( path );
response.addCookie( deleter );
}
我們簡單地分析一下上面的代碼:
➊ 的作用是清除remember me這個Cookie,這是針對網站有remember這個功能來說的。
➋ 是使得當前的會話無效,這樣即使當前的會話ID泄露出去了,***者也無法用這個會話ID進行登錄。
➌ 的作用是清除JSESSIONID這個Cookie。
➍ 使deleter(與傳遞進來的Cookie同名)立即無效。
本文節選自《Web應用安全威脅與防治——基于OWASP Top 10與ESAPI》
王文君 李建蒙 編著
電子工業出版社出版