Spring Security는 로그인시 예외를 비롯해 많은 정보를 세션(HttpSession)에 저장한다.
이 경우 로그인이 공격 대상이 될 때 로그인 URL에서 세션을 폭발적으로 생성하게 되고 이로인해 메모리 폭증이 발생한다. 이는 결과적으로 다시 매우 잦은 Full GC를 유발하게 된다.
따라서 공격에 노출될 가능성이 있는 사이트는 최소한 로그인의 경우에 세션을 생성하지 않도록 다양한 처리가 필요하다. 혹은 세션을 생성하더라도 공격시도는 Spring Security를 타기전에 다른 방법으로 차단할 수 있어야 한다.
로그인시에 세션에 저장하는 값들은 WebAttributes의 상수들 참조.
설정에서 create-session=“never”
를 준다
<http ... create-session="never">
이렇게 하면 UsernamePasswordAuthenticationFilter의 allowSessionCreation
값 등이 false로 변경된다.
<global-method-security> <expression-handler ref="myMethodSecurityExpressionHandler"/> </global-method-security>
<!-- This must go before the http element in order to be used by security:authorize tags using the access attribute --> <bean id="expressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"> <property name="roleHierarchy" ref="roleHierarchy" /> <!-- 꼭 필요한지는 의문 --> </bean> <security:http auto-config="true" use-expressions="true" access-decision-manager-ref="accessDecisionManager"> ... </security:http> <!-- security:authorize tags using the url attribute will delegate to this accessDecisionManager --> <bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased"> <property name="decisionVoters"> <list> <ref bean="webExpressionVoter" /> </list> </property> </bean> <bean id="webExpressionVoter" class="org.springframework.security.web.access.expression.WebExpressionVoter"> <property name="expressionHandler" ref="expressionHandler" /> </bean> <!-- 꼭 필요한지는 의문 --> <bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl"> <property name="hierarchy"> <value> ROLE_A > ROLE_B ROLE_B > ROLE_AUTHENTICATED ROLE_AUTHENTICATED > ROLE_UNAUTHENTICATED </value> </property> </bean>
403 Forbidden
페이지가 뜬다.<access-denied-handler ref="accessDeniedHandler 빈"/> <!-- 혹은 에러 처리 주소 지정 --> <access-denied-handler error-page="/accessDenied.do" />
SpringSecurity는 로그인 혹은 권한 관련예외가 발생할 경우 세션에 해당 예외를 저장한다. (SimpleUrlAuthenticationFailureHandler의 saveException() 참조)
해당 예외는 WebAttributes.AUTHENTICATION_EXCEPTION의 값인 SPRING_SECURITY_LAST_EXCEPTION
으로 저장된다.
문제는 기계화된 로그인 공격이 들어올 경우 모든 리퀘스트는 새로운 세션으로 간주되며 로그인 실패 예외들이 모두 세션에 저장되어 메모리 고갈을 일으킨다는 점이다. 이 때문에 AuthenticationFailureHandler를 SimpleUrlAuthenticationFailureHandler를 상속하여 구현하면서 saveException()
을 호출하지 않도록 하는 것이 좋다.
혹은 설정에서 create-session=“never”
를 준다
<http ... create-session="never">
saveException()을 호출하지 않도록 처리한 구현체를 다음과 같이 설정해 준다.
<form-login ... authentication-failure-handler-ref="AuthenticationFailureHandler구현체" />
이는 로그인 실패에 대한 것이며 권한 없음에 대한 예외는 다른 문제이다.
JSP에서 저장된 예외를 메시지 출력에 사용하는 경우가 있을 수 있는데, 이때는 JSP에서도 삭제하도록 해야 한다.
<c:remove var="SPRING_SECURITY_LAST_EXCEPTION" scope="session"/>