if (!this.securityContextRepository.containsContext(request)) { Authenticationauthentication= SecurityContextHolder.getContext().getAuthentication(); if (authentication != null && !this.trustResolver.isAnonymous(authentication)) { try { // 최대 생성 개수를 넘어섰는지?, Session 고정 공격이 들어왔는지? 등 // Session에 대한 인증을 진행한다. this.sessionAuthenticationStrategy.onAuthentication(authentication, request, response); } catch (SessionAuthenticationException ex) { this.logger.debug("SessionAuthenticationStrategy rejected the authentication object", ex); SecurityContextHolder.clearContext(); this.failureHandler.onAuthenticationFailure(request, response, ex); return; }
this.securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response); } else { if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) { if (this.logger.isDebugEnabled()) { this.logger.debug(LogMessage.format("Request requested invalid session id %s", request.getRequestedSessionId())); } if (this.invalidSessionStrategy != null) { this.invalidSessionStrategy.onInvalidSessionDetected(request, response); return; } } } } chain.doFilter(request, response); }
Session 관리를 위한 SessionAuthenticationStrategy
SessionAuthenticationStrategy 는 Session 이 존재하는지 확인하거나 Session 고정 공격에 대한 보호를 위해 Session Id를 변경한다.
동시성 Session 제어를 위한 - ConcurrentSessionControlAuthenticationStrategy
ConcurrentSessionControlAuthenticationStrategy 은 한 사용자가 만들 수 있는 Session 이 최대 생성 개수 를 넘어갔는지 확인한다.
@Override publicvoidonAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) { intallowedSessions= getMaximumSessionsForThisUser(authentication); if (allowedSessions == -1) { // We permit unlimited logins return; } List<SessionInformation> sessions = this.sessionRegistry.getAllSessions(authentication.getPrincipal(), false); intsessionCount= sessions.size(); if (sessionCount < allowedSessions) { // They haven't got too many login sessions running at present return; }
// 해당 사용자로 만들어진 Session의 개수와 허용된 Session 생성 개수를 비교한다. if (sessionCount == allowedSessions) { HttpSessionsession= request.getSession(false); if (session != null) { for (SessionInformation si : sessions) { if (si.getSessionId().equals(session.getId())) { return; } } } }
// Session이 최대치 보다 많이 생성된 경우에 대한 처리를 진행한다. allowableSessionsExceeded(sessions, allowedSessions, this.sessionRegistry); }
allowableSessionsExceeded 메소드는 현재 사용자의 인증에 대한 예외 처리를 진행하는 방법과 이전 사용자 Session 정보를 만료하는 방법 이 있다.
protectedvoidallowableSessionsExceeded(List<SessionInformation> sessions, int allowableSessions, SessionRegistry registry)throws SessionAuthenticationException {
// 현재 사용자가 인증을 못하도록 예외를 발생시킨다. // Session이 허용된 개수보다 많이 만들어졌거나, Session 자체가 없을 경우 SessionAuthenticationException 을 발생시킨다. if (this.exceptionIfMaximumExceeded || (sessions == null)) { thrownewSessionAuthenticationException( this.messages.getMessage("ConcurrentSessionControlAuthenticationStrategy.exceededAllowed", newObject[] { allowableSessions }, "Maximum sessions of {0} for this principal exceeded")); }
// 이전 사용자 Session 정보를 만료 한다. sessions.sort(Comparator.comparing(SessionInformation::getLastRequest)); intmaximumSessionsExceededBy= sessions.size() - allowableSessions + 1;
// 첫번째 사용자 정보를 가져와 만료한다. List<SessionInformation> sessionsToBeExpired = sessions.subList(0, maximumSessionsExceededBy); for (SessionInformation session : sessionsToBeExpired) { session.expireNow(); } }
Session 고정 공격 보호를 위한 - AbstractSessionFixationProtectionStrategy
AbstractSessionFixationProtectionStrategy 는 Session 고정 공격 보호 공통적인 로직을 수행시키기 위해 만들어진 추상 Class
Session을 가져온다. 만일 Session이 없을 경우 새로 생성한다.
Session 고정에 대한 적절한 처리를 진행한다.(Session Id를 변경)
Session Id가 변경 됐는지 확인한다.
SessionFixationProtectionEvent 이벤트를 발생한다.
AbstractSessionFixationProtectionStrategy.java
@Override publicvoidonAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) { // 만들어진 Session이 있으면 가져온다. booleanhadSessionAlready= request.getSession(false) != null; if (!hadSessionAlready && !this.alwaysCreateSession) { return; } // Session을 생성한다. HttpSessionsession= request.getSession(); if (hadSessionAlready && request.isRequestedSessionIdValid()) { String originalSessionId; String newSessionId; Objectmutex= WebUtils.getSessionMutex(session); synchronized (mutex) { originalSessionId = session.getId(); // Session 고정에 대한 적절한 처리를 진행한다.(Sessio Id를 변경) session = applySessionFixation(request); newSessionId = session.getId(); }
if (originalSessionId.equals(newSessionId)) { 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"); } else { if (this.logger.isDebugEnabled()) { this.logger.debug(LogMessage.format("Changed session id from %s", originalSessionId)); } } onSessionChange(originalSessionId, session, authentication); } }
Session Id를 변경 - ChangeSessionIdAuthenticationStrategy
ChangeSessionIdAuthenticationStrategy 는 AbstractSessionFixationProtectionStrategy 상속한 Class 다 ChangeSessionIdAuthenticationStrategy 는 Session 고정 공격 보호를 위한 방법으로 Session Id를 변경 한다.