쿠키와 SameSite, Secure, HttpOnly

2025. 4. 17. 15:40·Web-Spring

상황

네이버카페의 경우 cafe.naver.com으로 본 네이버의 도메인에서 서브도메인을 사용한다.

이와 같이 현재 개발중인 프로젝트도 서브도메인 양식을 사용하게 되는데,

이에 따라 프론트에서도 서브도메인별 서로 다른 레포지토리를 활용한다고 들었다.

 

그러면 중요한것이 인증정보가 서브도메인별로 유지되어야 하는데, 이를 위해서 SSO라는 걸 도입하기도 한다.

당장에 인증 체계를 빨리 구현하고 다른 도메인의 비즈니스 로직을 구현해야 한다고 판단했고,

쿠키를 통해 서브도메인간 인증정보를 유지해야겠다는 생각이 들었다.

 

이 과정에서 쿠키를 추가할때 HttpServletResponse에 addCookie 메소드를 통해서 수행되고

흔히 Spring에서 쿠키를 다룬다고 하면 JDK 21 기준 jakarta.servlet.http.Cookie 를 사용할 것이다.

그리고 또 흔히 보안을 위해서 Secure, HttpOnly, SameSite를 아무생각없이 걸기도 한다.

 

본 글에선 위의 속성들의 각각의 역할과 어떤 일이 있엇는지를 기술한다.

 


쿠키의 주요 속성들

내가 쿠키에서 사용하는 속성들은 다음과 같다.

  • MaxAge: 만료시간 설정, 단위는 초단위, 0으로 설정하면 즉시 만료시키는 것
  • Path: 클라이언트에서 아래의 Domain으로 부터 경로로 지정되며, 기본은 "/"이고 그 하위 경로까지 요청에 포함된다.
  • Domain: 클라이언트에서 해당 도메인에서 하위 도메인까지의 요청에서 쿠키가 함께 전송된다.
  • Secure: true라면, 클라이언트의 프로토콜이 Https 연결일때만 전송된다.
  • HttpOnly: true라면, Javascript로 해당 쿠키 접근을 막아준다.
  • SameSite: 쿠키가 다른 도메인에서 발생한 요청에 포함될 수 있는지 여부를 제어
    • Strict: 외부 도메인에서 온 요청에는 절대 쿠키전송 안 함
    • Lax(Default): 외부 도메인의 GET 요청만 허용
    • None: 모든 크로스도메인 요청에도 쿠키전송, 단 Secure 필수

위에서 강조해놓은 부분은 브라우저 상태와 관련 있는 부분이라서, 백엔드 URL 혹은 경로와는 크게 관련 없다.

 

결국 위의 설정상에서 내가 원하는 "서브도메인 간 인증정보 유지"를 위해서는

Domain과 Path를 적절히 조합하고, HttpOnly와 Secure를 켜주며 그리고 SameSite를 None으로 설정해 두는 것이다.

 

SameSite=None이지만 왜 쿠키가 전송되지 못할까...

그런데 SameSite=None이어도 프론트에서 Axios나 fetch를 활용하여 요청을 보낼 때 쿠키가 전혀 포함되지 않는다.

그 이유는 아래의 브라우저 및 Javascript 정책 때문이다.

  • MDN Fetch Credentials: default 값으로는 same-origin이며, 그 외의 상황에서는 절대로 쿠키를 전송하지 않는다, 크로스 오리진일 때도 전송하고 싶다면 include 옵션을 사용해야 한다.
  • Chrome SameSite=None: SameSite=None을 사용하여 크로스 사이트 액세스용 쿠키를 지정해야 합니다. SameSite=None 속성이 있으면 HTTPS 연결을 통해서만 크로스 사이트 쿠키에 액세스 할 수 있도록 추가 Secure 속성을 사용해야 합니다. 

그럼 include는 무슨 의미인가?

브라우저 입장에서 "인증헤더 및 쿠키를 포함한 요청이며, 응답받았을 때 JS로 접근이 가능하면 좋겠습니다."라는 의미를 요청에 포함하는 것이다. 

 

이제 쿠키가 잘 전송될 거라고 판단하여 요청을 보내면 이번엔 CORS 가 터질 것이다.

 

즉, 정상적으로 백엔드가 처리하고 응답을 보내지만 크로스 사이트이기 때문에 브라우저에서 응답을 차단하는 것이다. 

 

그래서 백엔드도 Access-Control-Allow-Credentials: true로 설정해야 한다.

 

여기까지 종합해 보면 백엔드에서 Set-Cookie 헤더로 쿠키를 설정해 달란 요청을 보내면,

클라이언트인 브라우저는 Credentials를 include로 설정해서 쿠키를 포함시킬 수 있을 때 포함되도록 해야 한다.

또한 백엔드는 해당 쿠키를 받아들이도록 약속된 오리진이라는 걸 Access-Control-Allow-Credentials: true로 설정해야 한다.

 


쿠키에 MaxAge가 0으로 설정해도 삭제되지 않는 문제

Spring에서 원하는 쿠키를 꺼내려면 HttpServletRequest 객체에서 Cookie 배열을 꺼내어 원하는 name이 나올 때 break 하면 된다.

public class Controller {
	
    private void getTokensFromRequest(HttpServletRequest request) {

        Cookie[] cookies = request.getCookies();
        if (cookies == null) {
           	return;
        }
        String name = "찾을 이름"
        for (final Cookie cookie : cookies) {
            if (name.equals(cookie.getName())) {
                System.out.print(cookie);
            }
        }
    }
}

 

만약 삭제가 하고 싶다면 setMaxAge(0)으로 설정하면 된다.

그런데 응답헤더에 Set-Cookie에도 Max-age=0인데, 개발자도구에 여전히 MaxAge가 팔팔한 체로 남아있는 사태가 벌어지고 만다.

 

이유는 RFC 6265 To remove a cookie 같이 처음에 Set-Cookie로 설정한 name 뿐만 아니라,

Domain속성과 Path가 같아야지 동일한 쿠키라고 판단한다.

따라서 MaxAge가 안 먹혔던 것이고, 초기에 쿠키를 설정할 때와 동일한 Domain 및 Path를 설정해 줌으로써 버그를 해결했다.

 

'Web-Spring' 카테고리의 다른 글

Springboot에서 SpringSecurity는 어떻게 초기화되는가? - 상  (0) 2025.05.03
SpringSecurity에서 OAuth2 로그인 시 쿼리 파라미터 유지하기  (0) 2025.04.28
@JsonTypeInfo 를 통해 유연하게 Json과 Java객체 매핑하기  (0) 2025.04.14
JUnit  (2) 2023.12.12
mybatis & hikari 설정  (9) 2023.12.05
'Web-Spring' 카테고리의 다른 글
  • Springboot에서 SpringSecurity는 어떻게 초기화되는가? - 상
  • SpringSecurity에서 OAuth2 로그인 시 쿼리 파라미터 유지하기
  • @JsonTypeInfo 를 통해 유연하게 Json과 Java객체 매핑하기
  • JUnit
devKhc
devKhc
  • devKhc
    개발저장소 by 회창
    devKhc
  • 전체
    오늘
    어제
    • 분류 전체보기 (24)
      • Web-Spring (7)
      • CS (5)
      • Infra (3)
      • DB (1)
      • Java (3)
      • CodeTree (5)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Springsecurity
    SpringBoot
    이중모드와 다중모드
    JsonTypeInfo
    코드트리조별과제
    인터럽트
    코딩테스트
    springboot #jenkins #CI/CD #Docker #EC2
    코드트리
    try with resources
    Multi-Processor
    Nginx #proxy #리버스 프록시
    set-cookie
    JsonSubTypes
    defaultoauth2authorizationrequestresolver
    인터럽트 #운영체제 #공룡책
    다중 코어 시스템
    모드비트
    samesite=none
    운영체제
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
devKhc
쿠키와 SameSite, Secure, HttpOnly
상단으로

티스토리툴바