Dev/Java

쿠키(Cookie)와 세션(Session), 그리고 토큰(Token) #1

두넌 2024. 4. 6.

배경

쿠키와 세션, 그리고 토큰은 HTTP 프로토콜의 stateless, connectionless 라는 특징을 어느정도 보완하기 위하여 등장했다

stateless : state(상태) 에 대한 정보를 저장하지 않는 HTTP의 특징 중 하나이다. 이전 상태에 대한 정보를 저장하지 않기 때문에, 서버에 연속된 요청을 보내더라도 서버는 사용자가 이전에 통신했음을 인지하지 못한다.
connectionless : connection(연결)을 지속하지 않는다. 하나의 요청에 대한 응답을 마치면, 서버는 즉시 클라이언트와 연결을 끊는다. 우리가 흔히 말하는 3way handshaking을 통한 연결의 수립을 매 요청마다 반복한다.

왜 두가지 특징을 보완해야 하는가?

특정 웹사이트가 있다고 해보자, 우리는 주문을 하기 위해서 로그인이라는 행위을 통해 인증 과정을 거쳐야 한다.

로그인 요청을 서버에 보내고, 유효한 사용자임을 서버로부터 응답 받았다. 그 후 주문을 하기 위해 주문 요청을 보냈다.

하지만 서버는 새로운 요청(주문 요청)을 허락해줄 수 없다. 이 사람이 로그인을 했는지 안했는지 기록을 하지 않았기 때문이다.

 

쿠키(Cookie)

특정 웹 사이트에 들어가면, 쿠키를 허용하시겠습니까? 라는 팝업 메시지를 본 적이 있을 것이다. 쿠키를 허용하게 되면 무슨 일이 일어나고, 사용자에게는 어떤 장점이 있을까?

쿠키란?

쿠키는 사용자 컴퓨터(브라우저)에 저장되는 상태 정보를 뜻한다. Spring Framework 를 사용하면 HttpServletResponse 객체를 사용할 수 있는 곳에서 다음과 같이 쿠키를 저장할 수 있다.

Cookie cookie = new Cookie("name", "value");
response.addCookie(cookie);

그리고 해당 과정을 거치면, 브라우저의 다음 세션(요청) 에서 개발자 도구(F12) > Application 탭에서 브라우저에 문자열 형태로 저장된 쿠키를 확인할 수 있다.

 

쿠키를 자세히 들여다 보면 (key, value) 형태로 저장되는 것과, value에는 String(문자열) 형태로 저장되는 것을 알 수 있다

// Cookie.java

public Cookie(String name, String value) {
	validation.validate(name);
	this.name = name;
	this.value = value;
}

CookieNameValidator 를 통하여 쿠키의 이름이 허용되는 문자열인지 검증한 후, 쿠키가 생성된다

 

사용자 컴퓨터에 저장된 쿠키 목록을 가져오고 싶다면 

public static Cookie findCookie(HttpServletRequest request, String name) {
	Cookie[] cookies = request.getCookies();

	if (Objects.nonNull(cookies)) {
		return Arrays.stream(cookies)
			.filter(cookie -> cookie.getName().equals(name))
			.findFirst()
			.orElseThrow(CookieNotFoundException::new);
	}

	throw new CookieNotFoundException();
}

다음과 같이 request.getCookies() 를 통하여 사용자의 쿠키 목록을 가져올 수 있다

이를 통해 매번 사용자가 요청을 보낼 때, 요청의 어딘가에 쿠키에 대한 정보도 함께 담아서 보낸다는 것을 알 수 있다

 

쿠키의 목적 ?

세션 관리

  • 서버에 저장해야 할 로그인, 장바구니, 스코어 등의 정보를 관리하기 위하여 사용한다

개인화

  • 사용자 개인의 정보를 저장하고 관리하기 위하여 사용한다. 예를 들자면, 브라우저의 라이트/다크모드 설정 등에 대한 정보가 일정 기간동안 유지될 수 있도록 사용하는 경우가 있다

트래킹

  • 사용자의 행동이나 기록 등을 분석하는 용도로 사용한다. 특정 웹 사이트에 들어가면, 해당 용도로 사용하는 쿠키를 허용할 것인지를 물어보는 창을 많이 봤던 경험이 있다
과거에는 클라이언트 측에 정보를 저장할 때 쿠키를 자주 사용했지만, 이 외에도 데이터를 클라이언트 측에 저장하는 방법이 많이 나오게 되면서 다른 방식을 사용하는 것을 권장하는 추세라고 한다.

모든 요청마다 쿠키가 함께 전송되기 때문에, 성능이 떨어지는 원인이 될 수 있다는 이유이다

> https://developer.mozilla.org/ko/docs/Web/HTTP/Cookies

 

쿠키의 옵션 ?

쿠키에는 많은 옵션들이 존재한다. maxAge, path, secure, httpOnly

Expires, maxAge

Expires 과 maxAge 라는 쿠키의 옵션이 있다. 이는 쿠키의 수명을 결정하는 속성이다.

먼저, 해당 두개의 속성이 존재하지 않는 쿠키는 세션 쿠키(Session Cookie) 라고 하며, 현재 세션이 끝날 때 삭제된다.

두가지 속성 중 하나라도 존재한다면, 이는 영속적인 쿠키(Permanent Cookie) 라고 하며, 다음과 같이 삭제된다

  • Expires : 해당 속성에 명시된 날짜에 삭제 (Expires=Wed)
  • Max-Age : 해당 시간(초) 이후에 삭제된다 (Max-Age=3600)
    • 두 옵션이 공존하는 경우 Max-Age 가 우선적으로 적용되며, 쿠키의 수명을 결정한다

 

Path

웹 서버의 특정 URL에서만 쿠키를 전송할 수 있다. Cookie는 HTTP 헤더의 Cookie 필드를 통해 서버로 전송된다.

  • Path 를 지정하지 않으면, Cookie를 생성했던 URL 범위에서 전송한다
  • Path 를 "/" 로 지정하면, 모든 URL 범위에서 전송한다
  • Path 를 "/abc/" 로 지정하면, "/abc/" 및 하위 URL 범위에서 전송한다

 

Secure

Secure Cookie 는 HTTPS 프로토콜 상에서 암호화된 요청일 경우에만 전송된다.

  • 단, Secure 일지라도, 민감한 정보는 절대 쿠키에 저장되면 안된다
  • Secure 옵션이 실질적인 보안을 제공하지는 않고, 본질적으로 쿠키는 안전하지 않기 때문이다

 

HttpOnly

HttpOnly 쿠키는 JavaScript의 Document.cookie API 에 접근할 수 없음

  • Cross-site Scripting(XSS) 공격을 방지하기 위하여 위 API에 접근할 수 없도록 한다.
    • XSS 란 스크립트 코드를 삽입하여 사용자가 고려하지 않은 기능을 작동시키는 것이다 
    • JavaScript를 사용할 필요가 없는 경우

예를 들면, 악의적으로 공격자가 웹 사이트에 document.cookie 를 호출하여 사용자의 쿠키에 대한 정보를 획득하고, 특정 웹으로 전송하는 스크립트를 삽입할 수 있다.

이 경우 HttpOnly 를 적용하지 않으면, document.cookie 를 호출하여 쿠키에 대한 정보를 획득할 수 있기 때문에 JavaScript 를 사용하지 않는 경우에는 HttpOnly 를 적용해 주는 것이 바람직하다.

 

동작 방식?

1. 클라이언트가 특정 페이지를 요청

2. 웹 서버가 쿠키를 생성하고, 쿠키에 정보를 담아 클라이언트에 응답(HTTP 헤더에 Set-Cookie 필드에 담아서 응답)

3. 응답으로 온 Set-Cookie의 내용을 클라이언트(브라우저)에 저장

4. 쿠키를 클라이언트에서 가지고 있다가, 서버에 요청할 때 요청과 함께 쿠키 전송(HTTP 헤더에 Cookie 필드에 담아서 요청)

Cookie: <cookie-list>
Cookie: name=value
Cookie: name=value; name2=value2; name3=value3

댓글