본문 바로가기
프로그래밍/스프링프레임워크

스프링 시큐리티에서 중복 로그인 방지 및 세션 고정 공격 방지

by pentode 2018. 4. 20.

스프링 시큐리티를 사용하면 동일한 아이디로 중복 로그인 방지 하는것을 간단히 구현할 수 있습니다. 또한 세션 고정 공격을 기본적으로 방어하도록 되어 있습니다. 이 두 가지를 같이 이야기 하는 이유는 두 가지가 같은 <session-management> 태그로 설정이 되기 때문입니다.


먼저 중복 로그인을 방지하는 방법을 알아보겠습니다. 예제 소스는 글 하단에 첨부하여 두었습니다. 이 예제는 "스프링프레임웍 - Spring Security(1) : 기본 설정"  글의 예제를 기본으로 하여 테스트 하였습니다.


스프링 시큐리티 설정파일인 /src/main/webapp/WEB-INF/spring/security-context.xml 파일의 <http> 부분에 다음을 추가합니다.


<http>

    <intercept-url pattern="/**" access="hasRole('USER')" />

    <form-login />

    <logout />


    <session-management invalid-session-url="/login">

        <concurrency-control max-sessions="1" expired-url="/login"/>

    </session-management>


</http>


<session-management> 태그를 이용해서 중복 로그인 방지를 설정합니다. 각 속성의 의미는 다음과 같습니다.


- invalid-session-url="/login" : 세션이 끊겼을때 이동 할 페이지 입니다.

- max-sessions="1" : 최대 허용 가능 중복 세션 수 입니다.

- expired-url="/login" :  중복 로그인이 일어났을 경우 이동 할 페이지 입니다.


위와 같이 설정하면 한 명이 로그인하고, 다른 곳에서 동일한 아이디로 로그인 하게 되면 먼저 로그인한 사람의 세션이 끊기게 됩니다. 먼저 로그인한 사람이 링크를 클릭하여 사이트내의 페이지를 이동하면 expired-url 로 지정된 곳으로 보내어집니다. 


위의 예에서는 세션이 유효하지 않을때와 중복 로그인이 발생했을때 모두 로그인페이지(/login)로 보내고 있습니다. 이것은 테스트를 단순히 하기 위해서 그런 것이고, 필요에 따라 중복 로그인으로 로그아웃 되었다는 안내 페이지를 만들수도 있겠습니다.


반대로, 첫 번째 로그인한 세션을 유지하고 두 번째 중복 로그인한 세션을 막으려면 다음과 같이 설정합니다.


<concurrency-control max-sessions="1" expired-url="/login" error-if-maximum-exceeded="true" />


error-if-maximum-exceeded="true" 속성을 지정하면 됩니다.





다음으로 세션 고정공격에 대한 방어 부분을 알아보겠습니다. 세션 고정 공격의 동작방식에 대해서 간단히 예를 들어 알아보겠습니다.


공격자가 임의의 세션 아이디를 URL 에 붙여서 링크를 만들어 글을 작성해 두고, 관리자가 그 링크를 클릭하도록 유도를 합니다. 관리자가 그 링크를 클릭하면 세션 아이디가 변경되므로 로그아웃 되어 버립니다. 관리자가 공격을 인지하지 못하고, 다시 로그인하게 되면 변경된 세션으로 관리자 권한을 가지게 됩니다. 공격자가 이 세션아이디를 사용하여 접속하면 관리자 권한을 갖게 되는 것입니다. 세션 고정 공격을 방어하는 기본적인 방법은 로그인시에 세션 아이디를 변경하도록 하는 것입니다.


스프링 시큐리티를 사용하면 기본적으로 세션 고정 공격을 방어하도록 설정되어 있습니다. 직접 설정은 다음과 같이 할 수 있습니다.


<session-management invalid-session-url="/login" session-fixation-protection="migrateSession">

    <concurrency-control max-sessions="1" expired-url="/login" />

</session-management>


세션 고정 공격에 대응 하는 방식을 몇가지로 설정할 수 있는데, 기본 값은 서블릿 스펙에 따라 달라진다고 합니다.


Servlets 3.0 또는 그 이전 버전의 경우 "migrateSession" 값이 기본으로 설정됩니다. Servlets 3.1 이상이면 "changeSessionId" 값이 설정되어 집니다. Servlets 3.1 부터 HttpServletRequet 객체에서 제공되는 changeSessionId() 메소드가 사용되어 지는 것입니다. 이 두가지 방식은 모두 세션아이디는 변경하고, 세션의 내용을 그대로 유지방식으로 동작합니다.


이 외에도 두 가지 방식이 더 있습니다.


- newSession : 새 세션이 만들어지고 기존 데이터는 보존되어지지 않습니다.

- none : 세션 고정공격 방어를 사용하지 않습니다.



추가로 전자정부표준프레임워크의 스프링 시큐리티 간편 설정에서 중복로그인을 방지하는 방법을 알아보겠습니다. 


web.xml 에 다음 리스너를 추가합니다. 템플릿 프로젝트에 이미 추가되어 있을 것입니다.


<listener>

    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>

</listener>


/src/main/resources/egovframework/spring/com/context-security.xml 파일 입니다.


<egov-security:config id="securityConfig"

    loginUrl="/uat/uia/actionSecurityLogin.do"

    logoutSuccessUrl="/uat/uia/actionMain.do"

    loginFailureUrl="/uat/uia/actionSecurityLogin.do?login_error=1"

    accessDeniedUrl="/sec/ram/accessDenied.do"


    concurrentMaxSessons="1"

    concurrentExpiredUrl="/uat/uia/egovLoginUsr.do"


    ...

/>


- concurrentMaxSessions="1" : 최대 허용 가능 중복 세션 수 입니다.

- concurrentExpiredUrl="/uat/uia/egovLoginUsr.do" : 중복 로그인 발생시 보내어질 URL 입니다.


세션의 동시성 제어를 위해서 HttpSessionEventPublisher를 반드시 포함 하여야 한다고 문서에는 되어 있었으나, 이 예제에서는 리스너를 추가하거나 빼는데 상관없이 동작하였습니다. 전자정부 프레임웍 예제에서는 리스너가 없으면 중복 로그인 제어가 동작하지 않았습니다.  이 부분은 점더 확인을 해 보아야 할것 같습니다.


이것으로 스프링 시큐리티에서 중복로그인 방지 및 세션 고정 공격 방어를 하는 방법에 대해서 알아보았습니다.


※ 예제소스


반응형