Spring

[SpringBoot] 쿠키, 세션 개념 정리

꾸준함. 2021. 7. 29. 23:53

개요

이번 포스팅에서는 로그인 기능을 구현할 때 꼭 필요한 개념인 쿠키와 세션에 대해 정리해보겠습니다. 

실제 로그인과 관련된 코드 및 설명은 다음 글에서 정리하겠습니다.

 

쿠키

  • 서버에서 요청에 대한 응답으로 클라이언트로 전달해주는 정보
  • 클라이언트가 서버에서 받은 쿠키를 저장하고, HTTP 요청 시 서버로 전달하는 정보
  • 위 두 정보는 HTTP Header에 저장이 됨
    • Set-Cookie: 서버에서 클라이언트로 쿠키 전달
    • Cookie: 클라이언트가 서버에서 받은 쿠키를 저장하고, HTTP 요청 시 서버로 전달하는 정보

 

쿠키 - 생명주기

  • Set-Cookie 내 expires라는 필드를 참고하면 쿠키 만료 날짜 및 시간을 알 수 있음 (GMT 기준)
  • Set-Cookie 내 max-age 필드는 마지막 요청으로부터 몇 초 동안 쿠키가 유지되는지 확인 가능
  • 세션 쿠키: 만료 날짜를 생략할 경우 브라우저 종료 시까지 유지
  • 영속 쿠키: 만료 날짜를 입력하면 해당 날짜까지 유지

 

쿠키 - domain

  • 도메인을 명시할 경우 명시한 도메인 및 서브 도메인 내에서만 쿠키 접근 가능
    • domain = naver.com일 경우
    • naver.com 뿐만 아니라 sports.naver.com에도 쿠키 접근 가능
  • 도메인을 생략할 경우 현재 도메인에만 쿠키 접근 가능
    • domain = naver.com일 경우
    • naver.com 에는 접근 가능하지만 sports.naver.com 에는 접근 불가능

 

쿠키 - path

  • 경로를 명시하지 않는 경우 path = / 이기 때문에 모든 페이지에 접근 가능
  • 경로를 명시하는 경우 경로를 포함한 하위 경로 페이지만 쿠키가 접근 가능
    • path = /home으로 지정된 경우
    • /home, /home/1, /home/1/2와 같이 home 하위 경로 접근 가능
    • /newhome 접근 불가능

 

쿠키를 사용하지 않는 상태에서 로그인하는 경우

  • 예상 결과: 클라이언트가 로그인 한 이후부터는 해당 애플리케이션 내 다른 페이지로 가더라도 로그인한 상태로 이동
  • 실제 결과: 클라이언트가 로그인할 때만 서버가 로그인한 유저를 인식하고 다른 페이지로 가면 또다시 로그인하지 않은 상태라고 인식
  • 이러한 일이 발생하는 이유는 HTTP가 기본적으로 Stateless 프로토콜이기 때문
    • 클라이언트와 서버 간 요청과 응답을 주고 받은 이후에는 연결이 끊어짐
    • 클라이언트가 다시 요청 시 서버는 이전 요청에 대한 정보를 지니고 있지 않음
    • 정리를 하자면, 클라이언트와 서버는 서로 상태를 유지하지 않음

 

* 클라이언트와 서버각 지속 연결 상태를 유지하도록 설정했더라도 만료 시간이 존재

 

쿠키 사용하지 않을 경우

 

해결책

  • 그렇다면 매 요청마다 쿼리 파라미터로 로그인한 유저의 정보를 전달하면 해결이 되지 않을까?
    • 이럴 경우 모든 요청에 사용자 정보가 포함되야하기 때문에 개발 공수가 어렵고
    • 보안 문제를 야기할 수 있기 때문에 현실적으로 어려움 (쿼리 파라미터를 통해 사용자 정보 유추 가능)
  • 따라서, 쿠키를 사용하여 위 문제를 해결하자

 

쿠키를 사용한 상태에서 로그인할 경우

  • 서버는 로그인 요청이 성공할 경우 응답 헤더 내 Set-Cookie로 사용자 정보 전달
  • 웹브라우저 내 쿠키저장소가 있으므로 브라우저는 사용자 정보를 쿠키 저장소에 저장
  • 클라이언트에서 요청 시 쿠키 저장소에서 쿠키 꺼내 모든 요청에 자동으로 포함 (네트워크 트래픽을 추가로 유발하는 것이 단점)
  • 모든 요청에 자동으로 쿠키를 포함할 경우 쿼리 파라미터에 사용자 정보를 전달하는 것처럼 보안 문제 야기
    • 쿠키 값은 클라이언트에서 강제로 변경 가능
    • 해커가 Man in the Middle Attack 방식을 사용하여 쿠키 값을 탈취 후 다른 값을 쿠키에 넣어 전송 가능
    • 따라서, 주민등록번호, 신용카드 번호, 비밀번호 등과 같이 보안에 민감한 데이터는 쿠키에 저장하면 안 됨
    • 또한, 쿠키 값이 규칙적이어서 유추가 가능하면 사용자가 쿠키 값을 위변조 하여 다른 고객 정보를 탈취도 가능
      • id=1, 2, 3,... 이런 식으로 쿠키 값이 전달될 경우 쿠키 내 id 값을 변경하여 다른 고객 정보 확인 가능
      • 따라서, UUID와 같이 랜덤 값을 쿠키에 저장하고 해당 값과 사용자 정보를 서버 내에서 1:1 매칭을 시켜 사용자 정보를 서버 내에서만 알 수 있도록 처리하는 것이 중요

 

* 아래 예시처럼 쿠키에 id 값을 그대로 노출시켜서는 안 되지만 간단한 예시이므로 그림에서는 id 값을 전달한 것처럼 표현

 

 

쿠키 보안 부연 설명

  • 기본적으로 쿠키는 http, https 프로토콜을 구분하지 않고 전송이 되지만 Secure 옵션을 적용하면 https인 경우에만 전송 가능
  • HttpOnly 옵션
    • XSS 공격 방지 목적
    • 자바스크립트에서 접근 불가
    • HTTP 전송에만 사용
  • SameSite 옵션
    • XSRF 공격 방지 목적
    • 요청 도메인과 쿠키에 설정된 도메인이 같은 경우만 쿠키 전송
    • 비교적 최신 버전 브라우저에만 적용 가능하므로 브라우저가 지원하는지 확인 후 적용 필요

 

세션

  • 쿠키는 클라이언트에서 저장하는 반면, 세션은 서버에서 저장하고 있는 정보
  • 세션은 아래와 같이 크게 3가지 기능 제공
    • 세션 생성
      • 각 클라이언트 고유 세션 ID를 부여하며 이는 UUID처럼 중복될 확률이 매우 적음
      • 세션 ID는 세션 저장소 내 보관
      • 세션 ID로 응답 쿠키를 생성해 클라이언트에 전달
    • 세션 조회
      • 클라이언트가 요청을 전달한 쿠키 내 세션 ID를 통해 세션 저장소에 보관한 값 조회
    • 세션 만료
      • 클라이언트가 요청으로 전달한 쿠키 내 세션 ID를 통해 세션 저장소에 보관한 값을 찾고 제거 

 

로그인 시 쿠키와 세션 모두 사용

  • 앞서 쿠키만 사용할 경우 여러 가지 보안 문제를 야기할 수 있었음
  • 아래와 같이 세션과 쿠키를 사용하여 보안 문제를 어느 정도 방지 가능

 

 

위와 같이 세션과 쿠키를 모두 사용할 경우 아래와 같은 보안 문제 해결 가능

  • 쿠키 값이 변조 가능하지만 sessionId는 불규칙적이기 때문에 다른 고객 정보가 나올 확률이 매우 적음
  • 쿠키는 클라이언트 사이드에 저장되기 때문에 노출되기 쉽지만 sessionId는 노출이 돼도 위험도가 매우 적음
  • sessionId가 불규칙적이더라도 man in the middle attack을 통해 탈취한 sessionId를 그대로 사용할 경우 고객 정보 노출될 위험이 존재
    • 세션의 만료시간을 짧게 유지하거나 ip가 갑자기 중국, 북한, 러시아 ip로 바뀔 경우 세션 값을 만료시키는 방법으로 대처 가능

 

* 서버 용량이 허용된만큼 세션을 생성할 수 있으나 가급적 최소한의 정보만 세션 내 저장하도록 하는 것을 권장합니다.

 

HttpSession 부연 설명

  • 세션을 생성하거나 조회할 때 HttpServletRequest의 getSession 메서드 파라미터로 boolean 값이 넘어가는데 디폴트는 true
    • true를 넘길 때는 세션이 있을 경우 기존 세션을 반환하고
    • 기존 세션이 없을 경우 새로운 세션을 생성해서 반환
    • 따라서, 신규로 세션을 생성할 때는 파라미터를 굳이 넘기지 않아도 됨
  • 반면, 세션을 조회하는 목적일 경우 신규로 세션을 생성할 필요가 없으므로 getSession 메서드 파라미터로 false를 넘김
  • 세션 데이터를 보관할 때는 HttpServletRequest의 setAttribute 메서드를 통해 key, value 형식으로 저장, 세션 데이터를 조회할 때는 getAttribute 메서드에 파라미터로 key 값을 전달하여 조회
    • ConcurrentHashMap과 비슷한 동작 방식
  • 서블릿을 통해 HttpSession 생성 시 JSESSIONID의 이름으로 쿠키가 생성되며 추정하기 매우 어려운 랜덤 값이 포함됨
    • 로그인을 처음 시도하면 URL 뒤에 jsessionid가 쿼리파라미터로 붙는 것을 확인할 수 있음
    • 이는 해당 브라우저가 쿠키를 지원하는지 유무를 모르기 때문에 URL에 jsessionid를 같이 전달하는 방식
      • 쿠키를 지원하는 것을 확인한 뒤로는 다음 요청부터는 jsessionid가 쿼리 파라미터로 전달 안됨
      • 쿠키를 지원하지 않을 경우 모든 요청에 jsessionid가 쿼리파라미터로 전달되면서 쿠키 역할을 하게 함
      • 위 현상을 방지하기 위해서는 기존 게시글 참고 https://jaimemin.tistory.com/1516
 

Tomcat에서 jsessionid가 URL에 붙는 것을 방지하는 설정

[개요] 웹 서비스를 개발하는 도중 redirect를 할 때 [리다이렉트한 URL;jsessionid=XXX]와 같이 url 뒤에 jsessionid가 붙는 경우가 있어 이를 방지하는 방법을 공유합니니다. [문제의 원인] 브라우저에서 쿠

jaimemin.tistory.com

 

출처

HTTP 웹 기본지식 (김영한 강사님)

인프런 스프링 MVC 2편 (김영한 강사님)

반응형