본문 바로가기

카테고리 없음

[Spring Boot] http 쿠키 전달 이슈

 

상황)

로그인 시스템을 구현하는 과정에서 Access Token과 Refresh Token을 사용하여 토큰 기반 인증을 설정했습니다. 로그인 시 서버는 클라이언트에게 Access Token은 헤더로, Refresh Token은 쿠키로 전달합니다. Access Token이 만료되면 Refresh Token을 사용하여 새로운 Access Token을 발급합니다. 하지만 로그아웃 시, 쿠키에 있는 Refresh Token을 삭제하려고 할 때 문제가 발생했습니다. 이 문제를 해결하는 과정을 단계별로 정리했습니다.

 

로그아웃 로직

 

로그인시 토큰 발급

 

 

Cors 설정

 

 

 

1) localhost(프론트) -> localhost(백엔드) : 쿠키가 잘 전달된다.

 

프론트 코드(로그인)

 

프론트 코드(로그아웃)

 

withCredentials는 XMLHttpRequest나 Fetch API에서 사용되는 옵션으로, 요청에 자격 증명(크레덴셜)을 포함할지 여부를 지정하는 설정입니다. 자격 증명에는 쿠키, 인증 헤더, TLS 클라이언트 인증서 등이 포함될 수 있습니다. 이를 통해 클라이언트와 서버 간의 보안된 통신을 가능하게 합니다.

 

 

2) localhost(프론트) -> EC2 IP (백엔드) : 쿠키가 잘 전달이 안된다.

 

로그인시 쿠키에 refresh token 발급

 

로그아웃 실패

 

url은 넘어오지만 쿠키는 넘어오지 않는다.

 

 

 

3) EC2 IP(프론트) -> EC2 IP (백엔드) : 쿠키가 잘 전달된다.

 

프론트 코드(로그인)

 

 

프론트 코드(로그아웃)

 

 

 

 

해결방법)

Host와 Origin이 다를 때 쿠키가 전달되지 않는 문제는 일반적으로 CORS(Cross-Origin Resource Sharing) 정책과 관련이 있습니다. 특히, 브라우저는 보안상의 이유로 크로스-오리진 요청 시 쿠키를 포함시키지 않도록 설정되어 있습니다. 이를 해결하려면 서버와 클라이언트 모두 올바르게 설정되어 있어야 합니다.

문제 설명

  • Host: 서버가 실제로 실행되고 있는 도메인 또는 IP 주소입니다.
  • Origin: 요청을 보내는 클라이언트의 도메인 또는 IP 주소입니다.

두 값이 다르면 브라우저는 CORS 정책을 적용하여 쿠키를 포함한 자격 증명을 기본적으로 차단합니다. 이 문제를 해결하기 위해서는 서버에서 Access-Control-Allow-Credentials 헤더를 설정하고, 클라이언트에서 withCredentials 옵션을 사용해야 합니다.

 

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList("http://52.78.9.158:5173", "http://localhost:5173"));
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
    configuration.setAllowCredentials(true); // 자격 증명을 허용합니다.
    configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "access", "refresh"));
    configuration.setExposedHeaders(Arrays.asList("Authorization", "access", "refresh"));
    configuration.setMaxAge(3600L); // 1시간

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

 

const response = await axios.post(
    'http://52.78.9.158:8080/api/logout',
    {},
    {
        headers: {
            Authorization: `Bearer ${token}`,
        },
        withCredentials: true, // 자격 증명을 포함하도록 설정합니다.
    }
);

 

 

로그인 시

    private Cookie createCookie(String key, String value) {

        Cookie cookie = new Cookie(key, value);
        cookie.setMaxAge(24*60*60);
        //cookie.setSecure(true);  // https 통신 일때
        cookie.setPath("/");
        cookie.setDomain("52.78.9.158");  // 52.78.9.158 이거는 토큰발급됨
        cookie.setHttpOnly(true);

        return cookie;
    }

 

로그아웃 시

        // Refresh 토큰 Cookie 값 0
        Cookie cookie = new Cookie("refresh", null);
        cookie.setMaxAge(0);
        cookie.setPath("/");
        cookie.setDomain("52.78.9.158");  // 52.78.9.158 이거는 토큰발급됨
        cookie.setHttpOnly(true);
        httpResponse.addCookie(cookie);
        httpResponse.setStatus(HttpServletResponse.SC_OK);

 

setDomain 메서드는 쿠키의 도메인을 지정할 때 사용되며, 클라이언트가 해당 도메인에서만 쿠키를 전송하도록 합니다. 만약 서버와 클라이언트가 동일한 도메인(또는 서브도메인) 내에서 통신하고 있다면 setDomain을 설정하는 것이 적절합니다.

 

 

결론) 

 

쿠키를 안전하게 전송하기 위해 두 가지 주요 조건이 있습니다:

  1. HTTPS를 통해 전송: 쿠키의 Secure 속성을 사용하면, 해당 쿠키는 HTTPS를 통해서만 전송됩니다.
  2. HTTP일 경우 동일 도메인: HTTP를 사용할 경우, 쿠키를 전달하기 위해 클라이언트와 서버가 동일한 도메인이어야 합니다. 이는 크로스 도메인 요청 시 보안 위험을 줄이기 위한 것입니다.