Spring ‐ 쿠키와 세션 - dnwls16071/Backend_Study_TIL GitHub Wiki
📚 쿠키(Cookie)
-
쿠키의 종류 : 영속 쿠키 / 세션 쿠키
- 영속 쿠키 : 만료 날짜 입력시 해당 날짜까지 유지
- 세션 쿠키 : 만료 날짜 생략시 브라우저 종료시까지 유지
-
쿠키의 보안 문제
- 쿠키 값은 임의로 변경할 수 있다. 결국 쿠키의 값을 변경하게 되면 한순간에 다른 사용자로 인식이 된다.
- 쿠키에 보관된 값은 훔쳐갈 수 있다. 훔친 쿠키를 통해 악의적인 요청을 계속 보낼 수 있다.
📚 세션(Session)
@PostMapping("/login")
public String loginV4(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult,
@RequestParam(defaultValue = "/") String redirectURL,
HttpServletRequest request) {
if (bindingResult.hasErrors()) {
return "login/loginForm";
}
Member loginMember = loginService.login(form.getLoginId(), form.getPassword());
if (loginMember == null) {
bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다.");
return "login/loginForm";
}
//로그인 성공 처리
//세션이 있으면 있는 세션 반환, 없으면 신규 세션을 생성
HttpSession session = request.getSession();
//세션에 로그인 회원 정보 보관
session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);
return "redirect:" + redirectURL;
}
- 서블릿(Servlet) : 클라이언트의 HTTP 요청을 받아 처리하고, 동적으로 HTTP 응답을 생성하는 Java 기반의 서버 사이드 컴포넌트
HttpServletRequest.getSession(true)
- 세션이 있으면 세션을 반환하나 세션이 없다면 세션을 생성해 반환한다.
- 기본적으로 true이므로 생략해도 무방하다.
HttpServletRequest.getSession(false)
- 세션이 있으면 기존 세션을 반환하고 없으면 null을 반환한다.
setAttribute()
getSesison()
으로 가져온 세션에 대해서 값을 키-값 쌍으로 넣는다.
- setAttribute() 메서드를 사용하면 하나의 세션에 여러 값을 저장할 수 있게 된다.
- 로그인 처리가 완료되면 Response에 자동으로 쿠키 값으로 JSESSIONID라는 것이 같이 담기게 된다.
- JSESSIONID는 내장 톰켓 서버와 같은 WAS에서 자동으로 발급해주는 식별자이다. 이는 HTTP의 Stateless 특성을 보완하기 위해 각 클라이언트를 구분하는 용도로 사용된다.
- 실제 발급되는 세션의 경우 서버 측의 세션 저장소라는 곳에서 보관한다. 이 저장소는 클라이언트 측에서 접근할 수 없다.
- 세션ID를 응답 쿠키로 만들어 반환하면 클라이언트 측 쿠키 저장소에서 이를 보관한다.
- 서버 측에서는 만든 세션ID에 대한 것을 세션 저장소에 저장한다.
- 클라이언트 측의 쿠키 저장소에서 보관하는 쿠키를 서버 측 요청을 보낼 때 함께 포함해서 보내게 된다.
- 그렇게 되면 서버 측에서 해당 쿠키 정보를 열람해 세션 ID를 서버 측 세션 저장소와 비교해 조회한다.
@PostMapping("/logout")
public String logoutV3(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
return "redirect:/";
}
invalidate()
: 해당 세션을 제거한다.
📚 서블릿 HTTP 세션
- 서블릿은 세션을 위해 HttpSession이라는 기능을 제공한다.
@GetMapping("/session-info")
public void sessionInfo(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session == null) {
return "세션이 없습니다.";
}
//세션 데이터 출력
session.getAttributeNames().asIterator()
.forEachRemaining(name -> log.info("session name={}, value={}", name, session.getAttribute(name)));
log.info("sessionId={}", session.getId());
log.info("getMaxInactiveInterval={}", session.getMaxInactiveInterval());
log.info("creationTime={}", new Date(session.getCreationTime()));
log.info("lastAccessedTime={}", new Date(session.getLastAccessedTime()));
log.info("isNew={}", session.isNew());
}
- sessionId : 세션 ID, JSESSIONID 값
- maxInactiveInterval : 세션 유효시간
- creationTime : 세션 생성일시
- lastAccessdTime : 세션과 연결된 사용자의 마지막 서버 접근 시간
- isNew : 새로 생성된 세션인가 아니면 클라이언트에서 서버로 JSESSIONID를 요청해서 조회한 세션인지 여부
- 서버 측 세션 저장소의 키 값은 JSESSIONID이다.
❗세션은 사용자가 로그아웃을 호출해야 세션이 삭제되면서 관리가 된다. 허나 대부분의 사용자는 로그아웃을 하지 않고 브라우저를 종료하기 때문에 세션이 그대로 남아있게 된다. ❗세션도 결국 자원이기에 타임아웃을 설정해 세션 자원을 관리할 필요가 있다.
[ 다중 서버에서의 세션 관리 ]
- 하나의 서버를 운영할 때 문제가 없으나 만약 다중 서버로 운영할 경우 세션 저장소는 하나의 서버에 하나의 세션 저장소로 대응되기 때문에 문제가 생긴다.
- 여러 서버를 띄워 사용하는 경우 세션 저장소를 별도로 구성해 여러 서버가 단 하나의 세션 저장소만을 가리키도록 해야 한다.