New Score :0
High Score :0
Run Best
NICE BUSINESS TYPE INDICATOR
3. 급전을 친구에게 빌렸는데 오늘이 돈을 주기로 한날.. 그런데 카드값을 내야하는 날도 오늘인데... 이걸 어쩌나...
4. 우리 회사는 중요한 의사 결정을 할때?
5. 열심히 일한 나를 위한 선물을 주고싶다. 어떤게 좋을까?
6. 은행에서 투자상품을 추천받았다. 어떤걸 가입하지?
7. 회사에서의 나는?
8. 꿈에서 깨어나니 20년 전으로 돌아갔다. 당신이 제일 먼저 하는일은?
9. 내가 인사 담당자라면 신규 입사자 채용 시 제일 중요하게 보는것은?
10. 회사에 정말 싫어하는 동료가 있다면?
11. 가난한 집의 가장이 되었다.. 자녀의 생일 날 선물은?
12. 평소 회사 출근 스타일은?
13.회사 체육대회 하는 날이다. 오늘 뭐하지?
14. 나의 업무 스타일은?
웹에서의 중복로그인 방지의 일반적인 방법
일반적으로 많이 사용되는 중복로그인 방지 기능의 개발에 대해, 러프한 설계 수준에서 정리해 보겠습니다. (아는데까지만..)
개요
- 하나의 userId로 동시에 두곳 이상에서 연결(로그인된..)될 수 없다는 뜻으로, 보안이슈에 해당합니다.
- 먼저 로그인한 연결이 A, 나중에 로그인을 시도하는 연결이 B라면, B가 로그인했을때 A의 연결을 끊는(튕겨내는) 방법, 또는 A의 연결을 유지하고 B의 로그인시도를 막는 방법이 있으며, 주로 전자의 방법을 취합니다.
히스토리
- 웹 이전의 CS 프로그램 시절에는 클라이언트의 연결을 직접 제어가 가능했으므로 기술적인 문제가 없었습니다.
- 웹으로 넘어와서, ActiveX가 횡행하던 시절에는 주로 ActiveX를 이용하여 중복로그인 방지를 구현했으며, 대부분 SSO, EAM 등의 보안관련 솔루션의 추가기능이었습니다.
이슈 리스트
- 이슈 #1. 로그아웃 이벤트 캐치
- 이슈 #2. 연결된 user들 관리
- 이슈 #3. 연결을 끊기(튕겨내기)
이슈 #1. 로그아웃 이벤트 캐치
- 웹에서의 중복로그인 방지의 첫번째 이슈이자 가장 큰 이슈는 stateless connection 특성에 기인하는데, 로그인 시점의 행위는 자유롭게 제어할 수 있으나 로그아웃 시점을 명확히 알 수 없으므로, 로그인된 연결의 종료시점 알수없다는 문제입니다. 로그아웃 버튼을 클릭하는 명시적 로그아웃의 경우에는 문제가 없지만, 브라우저를 닫아버리는 경우는 캐치할 방법이 없습니다. (물론, 주기적으로 헬스체크를 보내는 등의 편법은 가능합니다.)
- 이 문제는 WAS의 session timeout을 이용하는 것이 일반적인 해법으로, web.xml에 timeout 설정을 한 후, session의 라이프사이클을 리스닝하는 HttpSessionListener 또는 HttpSessionAttributeListener 인터페이스를 구현하여 web.xml에 등록합니다.
- HttpSessionListener를 구현하면 sessionDestroyed 메소드를 통해 session이 끊기는(invalidate, timeout) 이벤트를 받아 원하는 로직을 구현할 수 있습니다.
- HttpSessionAttributeListener를 구현하면 attributeRemoved 메소드를 통해 session이 끊기면서(invalidate, timeout) attribute가 remove되는 이벤트를 받아 원하는 로직을 구현할 수 있습니다.
- 인터넷에서 검색해보면 HttpSessionBindingListener가 많이 나타나는데, 이는 위의 두 리스너가 서블릿2.3에서야 추가되었기 때문이며 SessionBindingListener의 경우 session의 라이프사이클과 개념상 차이가 있고 tomcat 일부 버전에서 제대로 동작하지 않는 등의 문제가 있습니다.
- 위의 리스너들은 WAS에 따라 차이가 있기 때문에 반드시 테스트가 필요합니다. (예를들어, 세션 클러스터링된 웹스피어 일부 버전에서는 위의 리스너가 동작하지 않을 수 있습니다.)
이슈 #2. 연결된 user들 관리
- 연결(로그인) 시도시에 이미 연결된 user인지를 판별하기 위해 global한 저장소가 필요한데, application 레벨의 객체를 만들어 사용합니다.
- 멀티서버 지원 등을 위해서는 DB를 사용할 수 있으며, 일부 상용WAS의 경우 세션클러스터링을 위하여 DB를 사용하는 세션관리자를 가지고 있기도 합니다.
- 로그인한 사용자의 userId, sessionId 등을 HashMap 등에 넣어 저장하고 이를 static으로 만들거나 context에 넣어 관리합니다.
- 로그인 시에 userId를 저장소에 넣고, 로그아웃이나 session timeout시에(이슈 #1의 리스너들 사용) 해당 userId를 저장소에서 삭제합니다. (그전에, 세션 리스너에서 userId를 받기 위해 로그인시에 session에 userId를 setAttribute해야 합니다.)
이슈 #3. 연결을 끊기(튕겨내기)
- Action class나 필터 등을 사용하여 모든 행위시에 위의 저장소에 저장되어 있는 userId, sessionId 등을 현재의 정보와 비교한 후 필요에 따라 강제로 로그아웃(session을 invalidate) 합니다.
- SessionContext를 이용하여 WAS 상의 모든 세션 리스트를 가져와 sessionId에 해당하는 session을 끊는 방법이 존재하지만, 테스트 결과 잘 동작하지 않았습니다.
정리
- 저장소(HashMap<String,String>)를 만들어 Application context에 저장
- 로그인 시에 위의 저장소에 userId,sessionId를 put
- 로그인 시에 userId를 session에 setAttribute
- 로그인 시에 저장소에 이미 해당 userId가 존재하면 remove한 후 userId와 새 sessionId를 put
- WAS에 session timeout 설정 (web.xml)
- HttpSessionListener를 implements하여 class 생성. (web.xml에 리스너 등록)
- sessionDestroyed 메소드에서 event.getSession().getAttribute("userId")로 현재의 userId를 얻어 위의 저장소에서 remove
- 모든 행위시에, 저장소에 저장된 userId,sessionId를 현재 정보와 비교하여 동일하지 않으면 alert 후 강제 로그아웃
이상입니다.
문제 발견 시 또는 다른 좋은 방법을 아시는 분의 댓글을 특히 환영합니다.
출저: http://cafe.naver.com/hermeneus/33