Session fixation attack(會話固定攻擊)是利用服務器的session不變機制,借他人之手獲得認證和授權,然后冒充他人。如果應用程序在用戶首次訪問它時為每一名用戶建立一個匿名會話,這時往往就會出現會話固定漏洞。然后,一旦用戶登錄,該會話即升級為通過驗證的會話。最初,會話令牌並未被賦予任何訪問權限,但在用戶通過驗證后,這個令牌也具有了該用戶的訪問權限。
防止會話固定攻擊,可以在用戶登錄成功后重新創建一個session id,並將登錄前的匿名會話強制失效。Spring Security默認即可防止會話固定攻擊。具體實現方式[3.1版本]如下:HttpConfigurationBuilder的createSessionManagementFilters方法用於配置文件中的session-management屬性,並根據配置創建SessionManagementFilter。其首先讀取session-fixation-protection並存入sessionFixationAttribute變量,隨后,通過如下語句判斷是否需要進行會話規定漏洞保護
boolean sessionFixationProtectionRequired = !sessionFixationAttribute.equals(OPT_SESSION_FIXATION_NO_PROTECTION);
需要說明的是在上述語句之前,如果發現sessionFixationAttribute變量沒有賦值(例如,沒有配置session-management屬性),程序會采用如下語句確保缺省的session-fixation-protection=migrateSession
if (!StringUtils.hasText(sessionFixationAttribute)) {
sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
下面的判斷,如果您配置了session-management並啟用了concurrency-control,則向SessionManagementFilter注冊ConcurrentSessionControlStrategy類;否則如果上面代碼中的sessionFixationProtectionRequired = true或者配置了invalid-session-url,則向SessionManagementFilter注冊SessionFixationProtectionStrategy類,由於ConcurrentSessionControlStrategy繼承自SessionFixationProtectionStrategy,因此以上條件下,都會導致SessionFixationProtectionStrategy的策略被應用,而SessionFixationProtectionStrategy的策略,將在SessionManagementFilter中被執行,代碼如下
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
{
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
if (request.getAttribute("__spring_security_session_mgmt_filter_applied") != null) {
chain.doFilter(request, response);
return;
}
request.setAttribute("__spring_security_session_mgmt_filter_applied", Boolean.TRUE);
if (!this.securityContextRepository.containsContext(request)) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if ((authentication != null) && (!this.authenticationTrustResolver.isAnonymous(authentication)))
{
try {
this.sessionAuthenticationStrategy.onAuthentication(authentication, request, response);
......
回頭來看SessionFixationProtectionStrategy的onAuthentication方法,如下代碼中,字體加粗部分,先設置當前的session失效,再創建一個新的session
public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response)
{
boolean hadSessionAlready = request.getSession(false) != null;
if ((!hadSessionAlready) && (!this.alwaysCreateSession))
{
return;
}
HttpSession session = request.getSession();
if ((hadSessionAlready) && (request.isRequestedSessionIdValid()))
{
String originalSessionId = session.getId();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Invalidating session with Id '" + originalSessionId + "' " + (this.migrateSessionAttributes ? "and" : "without") + " migrating attributes.");
}
Map attributesToMigrate = extractAttributes(session);
session.invalidate();
session = request.getSession(true);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Started new session: " + session.getId());
}
if (originalSessionId.equals(session.getId())) {
this.logger.warn("Your servlet container did not change the session ID when a new session was created. You will not be adequately protected against session-fixation attacks");
}
transferAttributes(attributesToMigrate, session);
onSessionChange(originalSessionId, session, authentication);
}
}
最后,怎么關閉Spring Security的session-fixation-protection呢,由以上代碼分析知,除了將session-fixation-protection設置為null以外,還不能設置諸如concurrency-control或invalid-session-url屬性,舉例如下
<session-management session-fixation-protection="none" />
