이전에 알아본 쿠키만을 이용한 로그인 서비스를 실현하기에는 보안상 많은 문제점들이 있다. 이를 해결하기 위해서는 민감한 정보를 서버측에서 저장해야한다. 그리고 클라이언트와 서버는 추정 불가능한 임의의 식별자값으로 연결해야 한다.
세션은 위에서 말한 방법을 그대로 실현한다.
서버는 로그인한 사용자의 쿠키에 UUID
를 보낸다. 앞에서 살펴봤지만 쿠키는 name
과 value
가 있다. 예를 들어, name
에 mySessionId
라고 보낸다면 클라이언트의 쿠키는 아래와 같을 것이다.
Set-Cookie: mySessionId=qweqr-54453d-sfe84f6s-fdf54ef2-...
서버는 이제 고유한 UUID
와 회원 객체를 맵핑시켜놓으면 된다.
이제 세션을 사용해서 서버에서 중요한 정보를 관리하게 되었다. 덕분에 다음과 같은 보안 문제들을 해결할 수 있다.
세션은 제법 간단하게 직접 구현할 수도 있지만 서블릿에서 공식 지원하는 세션이 있다.
쿠키 이름이 JSESSIONID
이다.
Controller의 구현 함수에서 HttpServletRequest
를 파라미터로 받고나서 getSession()
을 통해 HttpSession
객체를 받을 수 있다. 없다면 새로 생성하게 된다.
public HttpSession getSession(boolean create);
세션의 create 옵션에 대해 알아보자.
HttpServletRequest 인스턴스를 request라고 하면
request.getSession(true)
request.getSession(false)
null
을 반환한다.세션에 로그인 회원 정보 보관
session.setAttribute("식별자", 회원 객체);
세션에 데이터를 보관하는 방법은 request.setAttribute(..) 와 비슷하다. 하나의 세션에 여러 값을 저장할 수 있다.
session.invalidate()
: 세션을 제거한다
session.getAttribute("식별자")
: 로그인 시점에 세션에 보관한 회원 객체를 찾는다.
스프링은 세션을 더 편리하게 사용할 수 있도록 @SessionAttribute
을 지원한다.
이미 로그인 된 사용자를 찾을 때 사용하면 된다. 참고로 이 기능은 세션을 생성하지 않는다.
@SessionAttribute(name = "loginMember", required = false) Member loginMember
파라미터에서 사용된다.
Member가 회원 클래스이고 loginMember에 세션을 통한 회원의 정보가 담긴다.
로그인을 처음 시도하면 URL에 jsessionid
를 포함하고 있는 것을 확인할 수 있다.
http://localhost:8080/;jsessionid=118F518B92983F871CF62D09F0DF59F2
쿠키를 지원하지 않는 웹 브라우저가 존재하는데 쿠키 대신 URL
을 통해 세션을 유지하는 방법이다. 이 방법은 URL
에 jsessionid
를 계속 포함해서 전달해야 한다. 타임리프 같은 템플릿은 엔진을 통해서 링크를 걸면 jsessionid
를 URL
에 자동으로 포함해준다. 서버 입장에서 웹 브라우저가 쿠키를 지원하는지 하지 않는지 최초에는 판단하지 못하므로, 쿠키 값도 전달하고, URL에 jsessionid 도 함께 전달한다.
URL 전달 방식을 끄고 항상 쿠키를 통해서만 세션을 유지하고 싶으면 다음 옵션을 넣어주면 된다.
application.properties
에
server.servlet.session.tracking-modes=cookie
sessionId
: 세션Id, JSESSIONID 의 값이다. 예) 5a849027-8a5e-4cd3-9d08-4a54d42bc161maxInactiveInterval
: 세션의 유효 시간, 예) 1800초, (30분)creationTime
: 세션 생성일시lastAccessedTime
: 세션과 연결된 사용자가 최근에 서버에 접근한 시간, 클라이언트에서 서버로 sessionId
( JSESSIONID )
를 요청한 경우에 갱신된다.isNew
: 새로 생성된 세션인지, 아니면 이미 과거에 만들어졌고, 클라이언트에서 서버로sessionId
( JSESSIONID )
를 요청해서 조회된 세션인지 여부세션 타임아웃 설정
스프링 부트로 글로벌 설정
application.properties
에서
server.servlet.session.timeout=?? : ??초, 기본은 1800(30분)
글로벌 설정은 분 단위로 설정해야 한다. 60(1분), 120(2분), ...
로그인 처리 방법 중 세션에 대해 알아보았다. HttpSession
이 기본적으로 제공되고 있어 따로 구현하는 일 없이 사용하면 굉장히 편해보인다. 하지만 세션은 메모리를 사용하는 일이므로 최소한의 정보만을 유지할 필요가 있어보인다. 최근에 JWT에 대해 알게됐는데 이 부분도 깊이있게 공부해봐야겠다.