Spring Cookie & Session

dev_314·2023년 1월 29일
0

Spring - Trial and Error

목록 보기
1/7

Cookie의 종류

영속 쿠키

  • 만료 날짜를 입력하면 해당 날짜까지 유효한 쿠키

세션 쿠키

  • 만료 날짜를 생략하면 브라우저 종료시 까지만 유효
  • Http, Server에서 사용되는 Session과 상관없는 개념

Spring에서 Cookie 다루기

@PostMapping("/login")
String login(HttpServletResponse response) {
	Cookie cookie = new Cookie("name", "value");
    response.addCookie(cookie);
}
  1. Cookie는 Servlet 기술 (javax.servlet.http.Cookie;)
  2. Cookie의 name, value는 모두 String 타입이어야 함
  3. 따로 날짜 정보를 설정하지 않았으므로, 위에서 생성된 Cookie는 세션 쿠키

HttpServeltRequest 사용

@PostMapping("/login")
String login(HttpServeltRequest request) {
	Cookie[] cookies = request.getCookies();
}

@CookieValue 사용

Spring은 편하게 Cookie를 다룰 수 있도록 @CookieValue annotation을 제공한다.

@PostMapping("/login")
String login(@CookieValue(name = "name", required = false) Long id) {
	if (id == null) {...}
}

name

  • 찾으려는 쿠키의 name을 설정

value

  • name 속성과 같은 역할 수행 (name의 alias)

required

  • 쿠키의 필수 여부를 설정
  • required = true가 기본값
String login(@CookieValue(name="name" required = true) Long id) {...}
  • 쿠키가 없는 경우 400 Bad Request를 응답함
String login(@CookieValue(name="name" required = false) long id) {...}
  • 쿠키 값이 없는 경우에는 id에는 null값이 들어감
  • 그런데 primitive 타입을 사용했으므로, 쿠키 값이 없는 경우 java.lang.IllegalStateException이 발생 & 500 Internal Server Error를 응답함 -> 특별한 이유가 없으면 Reference Type을 사용하자

defaultValue

  • 쿠키가 없는 경우 제공할 기본 값을 설정함
  • defaultValue를 사용 = 암시적으로 required = false

삭제 = 만료 = max-age를 0으로 만들기

public String logout(HttpServletResponse response) {
	// 만료시킬 쿠키와 동일한 이름의 쿠키를 새로 생성
    Cookie cookie = new Cookie("name", "value");
    cookie.setMaxAge(0); // max-age를 0으로 설정
    response.addCookie(cookie);
}

쿠키의 보안 문제

  1. 쿠키는 브라우저에서 조작 가능
  2. 쿠키는 탈취 가능

해결법

  1. 쿠키에 중요한 값을 직접 넣지말고, 임의의 값 (브라우저-서버만 해석할 수 있는 암호화된 값 등)을 사용
  2. 데이터에 만료 시간을 설정하기 -> 쿠키가 탈취되어도 만료시간으로 거를 수 있다.

Spring에서 Session 다루기

Spring에서 Session은 쿠키에 JSESSIONID:추정_불가능한_값형태로 저장된다.

무의식적으로 사용하는 Spring의 HttpSession은 톰캣의 HttpSession이고, 톰캣에 내부적으로 저장, 관리된다.

HttpServletRequest 사용하기

스프링은 Servlet을 통해 Session 기능을 제공한다.
javax.servlet.http.HttpSession

// 요청과 관련된 세션 객체가 있으면 그대로 반환, 없으면 새로 생성
HttpSession session = request.getSession();
// '없으면 새로 생성'이 기본값으로 사용된다. 
HttpSession session = request.getSession(true);
// 기존 값이 없어도 새로 생성 X (null 반환)
HttpSession session = request.getSession(false);

// 세션에 속성값을 할당, 여러 개 가능
session.setAttribute("name", "value");
// 속성 이름으로 데이터 찾아오기
Object name = session.getAttribute("name");
// Cookie에 저장된 세션 아이디 불러오기
String id = session.getId();
// 세션에 저장된 속성 이름 목록
Enumeration<String> attributeNames = session.getAttributeNames();

// 세션 유효 시간 (초) 
int maxInactiveInterval = session.getMaxInactiveInterval();
// 생성된 시간 (unix time 기준 몇 초 후에 생성됐는가)
long creationTime = session.getCreationTime();
// new Date(session.getCreationTime())로 날짜 확인 가능
// 마지막으로 접근한 시간 (unix time 기준 몇 초가 흘렀는가)
long lastAccessedTime = session.getLastAccessedTime();
// new Date(session.getLastAccessedTime()) 로 날짜 확인 가능
// 새로 생성된 세션인가
boolean isNew = session.isNew();

@SessionAttribute 사용

Spring은 편하게 Session을 다룰 수 있도록 @SessionAttribute annotation을 제공한다.

public String login(@SessionAttribute(name = "name") Member member) {
	...
}

세션 객체에 name이라는 이름으로 저장된 데이터를 불러온다.
이 기능은 새로 세션을 생성하지 않는다, 단순히 세션을 조회할 뿐

name

  • 세션 객체에 담긴 데이터를 찾아오기 위한 이름을 지정

value

  • name의 alias 역할

required

  • 요청과 관련된 세션이 존재하고, 해당 세션에 명시한 이름에 해당하는 데이터가 존재하는가를 표현
  • 세션이 존재하지 않거나, 세션 객체에 데이터가 없는 경우 예외가 발생

TrackingMode

Spring은 브라우저에게 쿠키를 통해 Session ID를 전달한다. 그런데 만약 브라우저가 Cookie 기능을 제공하지 않을 수도 있다.

이를 해결하기 위해, Spring은 쿠키로 세션 아이디를 전달할 뿐만 아니라, 다음처럼 Url에 세션 아이디를 붙여 전달한다. (Tracking Mode)
localhost:8080/;JSESSIONID=123456788

그런데 이 방식을 사용하면 사용자 인증이 필요한 모든 요청 URL에 세션 아이디를 붙여야 한다. 이를 ThymeLeaf같은 템플릿 앤진이 도와주기도 한다.

설정을 통해 TrackingMode를 사용하지 않을 수 있다.

// application.properties

server.servlet.session.tracking-mode=cookie

Session 만료시간 설정하기

일반적으로 사용자는 로그아웃 버튼을 눌러 명시적으로(?) 로그아웃을 수행하지 않는다. 대충 브라우저를 닫을 뿐

Http Protocol은 Connectionless이기 때문에, 사용자가 브라우저를 종료했는지 인식할 수 없다.
따라서 메모리 측면에서 서버의 Session을 효과적으로 정리해야 할 필요성이 있다.

이를 Session에 만료 시간을 설정함으로써 해결할 수 있다.
단순히 30분 뒤에 종료되도록 설정하면 안되므로(아직 사용중일 수도 있다),
사용자의 마지막 요청으로부터 30분 후에 세션을 제거한다.

마지막 접근 시간 후, 만료시간이 도달했을 때 세션을 제거하는 작업은 WAS(Tomcat)이 수행한다.

Spring boot를 사용해서 Global 설정하기

// application.properties

// 세션의 생명 주기를 60초로 설정, 기본 값은 1800(30분)
server.servlet.session.timeout=60 

// 60으로 나눠지는 단위의 시간으로 설정해야 한다.

특정 Session에는 다른 MaxInactiveInterval 설정하기

session.setMaxInactiveInterval(1800);

잡담

  1. 세션 = 메모리 소모 -> 세션에는 최소한의 데이터만 저장해야 한다.
  2. Web은 Domain에 의존하도록, Domain은 Web에 의존하지 않도록 설계해야 함
    -> 항상 의존관계를 단방향으로 구성해야 함
profile
블로그 이전했습니다 https://dev314.tistory.com/

0개의 댓글