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" />