본문 바로가기
프로젝트/텀블벅 클론 코딩

[ Spring / 사용자 인가 ] 2. 잃어버린 set-cookie를 찾아서

by zangsu_ 2023. 6. 6.

앞선 게시글에선 사용자 권한 유지를 위해 Session을 생성 해 주었다. 서버에서는 JSESSIONID에 대한 쿠키를 생성해 주었을 테지만, 응답에서는 set-cookie 헤더를 찾아볼 수 없었다.

 

HTTPS 통신

조금 더 찾아보니 쿠키를 사용하기 위해서는 HTTPS 통신을 사용해야 했다.

라고 적으면 너무 결과적인 내용만 말하는 것 같으니 조금 더 자세히 알아보자.

 

same-Site 문제

sameSite 속성은 보안을 위해 사용하는 쿠키의 속성중 하나로, 특정 상황에서 쿠키를 클라이언트로 전송할 수 있는지 제한하기 위한 속성이다.

  • sameSite = Strict
    • 동일한 사이트에서의 요청에만 쿠키를 전송한다.
    • CSRF 공격을 방지할 수 있음
  • sameSite = Lax
    • 기본적으로 Strict와 같으나, 별도의 예외 상황에 한해 쿠키 전송을 허용한다.
  • sameSite = None
    • 모든 요청에 대해 쿠키 전송을 허용한다.
    • 해당 속성을 사용하기 위해서는 secure 속성을 사용해야 한다.
      • secure 속성은 HTTPS 연결에서만 쿠키가 전송되도록 보장해 준다.

만약 다른 서버에서의 모든 요청에 대해 쿠키 전송을 허용한다면, 제 3자의 서버가 사용자와 서버 사이의 통신에 관여해 사용자의 권한을 탈취할 수 있다. 때문에 서버는 특정 신뢰할 수 없는 서버로의 요청(크로스 사이트 요청)에 대한 쿠키 전송을 제한해야 한다. 

현재 프로젝트의 FE는 localhost:3000, BE 서버는 도메인 호스팅(example.com이라 가정)을 사용하고 있기에 크로스 사이트 요청에 해당한다. 즉, samaSite 속성을 None으로 설정 해 주어야 하고, 이를 위해선 secure 속성을 추가로 사용해 주어야 한다. 그리고 secure 속성은 HTTPS 연결에서만 쿠키가 전송되기 때문에 HTTPS 연결을 사용해 주어야 한다.

HTTPS 연결은 아래 블로그의 도움을 받았다.

https://velog.io/@server30sopt/EC2-HTTPS%EB%A1%9C-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0

 

EC2 HTTPS로 연결하기

👾 작성자: 이승헌🐬 작성자의 한마디: https로 연결은 눈감고 한다우선 해당 글을 포스팅하기에 앞서 http에서 굳이 https로 연결하는 이유에 대해 이야기해보려 합니다.HTTP는 Hyper Transfer Protocol의

velog.io

 

spring 디렉토리 > src > main > resouces > application.properties 에서 자동으로 생성되는 쿠키의 속성 값에 sameSite을 사용하도록 설정해 주자.

//...//

server.servlet.session.cookie.domain = [도메인]
server.servlet.session.cookie.path = /
server.servlet.session.cookie.http-only= true
server.servlet.session.cookie.same-site=None
server.servlet.session.cookie.secure=true

 

CORS 정책

앞서 언급했던 것 처럼, 제 3자의 서버에서의 모든 요청을 허용해 둔다면 보안상 문제가 생길 수 있기 때문에 기본적으로 다른 Origin에서의 요청은 허용하지 않는다. 하지만, 모든 다른 서버에서의 요청을 허용하지 않는다면 웹 서비스의 통신에는 매우 많은 어려움이 존재할 것이다. 그렇기에 서로 다른 Origin에서의 요청을 허용하고, Resource를 공유하기 위한 정책이 필요하다. 이것이 CORS 정책이다.

 

이번 포스팅의 주제가 CORS는 아니기 때문에, CORS 정책에 대해 정말정말 잘 설명을 해 주신 인파님의 블로그를 남겨 둔다. 처음 읽으면 외계어일 수 있지만, CORS 정책 관련 문제를 만날 때 마다 반복해서 읽어보자.

https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-CORS-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-%F0%9F%91%8F

 

🌐 악명 높은 CORS 개념 & 해결법 - 정리 끝판왕 👏

악명 높은 CORS 에러 메세지 웹 개발을 하다보면 반드시 마주치는 멍멍 같은 에러가 바로 CORS 이다. 웹 개발의 신입 신고식이라고 할 정도로, CORS는 누구나 한 번 정도는 겪게 된다고 해도 과언이

inpa.tistory.com

 

서버에서 내보낸 응답을 확인할 수 있는 origin이 localhost:3000이어야 한다. 즉 클라이언트가 응답 메시지를 받았을 때, 해당 응답이 클라이언트에게 전송된 것임을 확인할 수 있어야 한다. 응답 헤더의 Access-Control-Allow-Origin 헤더에 클라이언트의 origin을 추가해 클라이언트가 해당 응답 메시지를 확인 할 수 있도록 하자.

 

이번 프로젝트에서는 jakarta.servlet.Filter 인터페이스를 구현하였다.

@Component
public class CORSFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {...}

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
    		throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;

        response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", 
        	"Origin, X-Requested-With, Content-Type, Accept, Authorization");
       //...//
    }

    @Override
    public void destroy() { ... }
}

해당 내용에 대해 좀 더 참고하고 싶다면, 내가 참고하며 많은 도움을 받은 아래 블로그를 확인하자.

https://wonit.tistory.com/572

 

[Spring Boot] CORS 를 해결하는 3가지 방법 (Filter, @CrossOrigin, WebMvcConfigurer)

Server Side Template 방식이 아닌 Front와 Back 으로 나눠서 인프라를 구성해본 경험이 있는 사람들에게는 Cors가 매우 친숙할 수 있다. 현재 개발 흐름에서 웹 프로젝트를 진행하다가 Cors 를 만날 확률은

wonit.tistory.com

 

쿠키 확인 하기

이제 Https 연결을 설정 했고, same-site 속성을 적용했으며 CORS 정책에 대한 처리를 해 주었다.

쿠키가 정상적으로 생성되는 것만 확인해 보면 된다!

페어님, 응답 헤더 확인 부탁 드립니다!

same-site 문제가 발생하는데요?

이전 게시글에서 말 했던가?

세상 일은 생각대로 돌아가지 않는다.

 

위에서 설정해 준 속성이 그대로 적용되지 않는 이유는 AWS의 ALB를 사용했기 때문이라고 한다. AWS ALB는 기본적으로 HttpOnly 속성은 적용하고, SameSite, Secure 속성은 적용하지 않기 때문에 타겟 그룹 설정에서 쿠키 설정을 변경해야 한다고 한다.

 

우선, 임시 봉합을 위해 수동으로 쿠키를 추가해 주자.

//...//
	HttpHeaders headers = new HttpHeaders();
    session.setAttribute(HttpConst.SESSION_USER_INDEX, userIndex);
    session.setMaxInactiveInterval(60 * 60 * 24);

    ResponseCookie cookie = ResponseCookie.from("JSESSIONID", session.getId())
            .domain("도메인 명")
            .path("/")
            .sameSite("None")
            .httpOnly(true)
            .secure(true)
            .maxAge(60 * 60 * 24)
            .build();
    headers.set("set-cookie", cookie.toString());
    
    return ResponseEntity.ok()
                .headers(headers)
                .build();

 

다시 회원가입 요청을 보내보자.

SameSite=None 속성을 가진 Set-Cookie 헤더를 확인할 수 있다.

이제 쿠키가 정상적으로 저장이 된다.

 

브라우저에 저장되어 있는 다른 도메인의 쿠키를 확인하기 위해선 해당 서버 도메인으로 접속 후 개발자 도구를 확인하면 된다고 한다.

 

 

Thanks to

아래는 위에 언급하지 않은 블로그들 중, 이번 포스팅에 서술한 과정을 진행하며 도움을 많이 받은 블로그 들이다.

 

https://velog.io/@ooooorobo/%EB%8B%A4%EB%A5%B8-%EB%8F%84%EB%A9%94%EC%9D%B8%EC%97%90-%EC%BF%A0%ED%82%A4-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0#%EC%9B%B9-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C%EC%97%90%EC%84%9C-%ED%95%B4%EC%95%BC-%ED%95%A0-%EC%9D%BC

 

다른 도메인에 쿠키 설정하기

서버와 클라이언트의 도메인이 다를 때 쿠키를 설정하고 CORS 에러를 해결하기

velog.io

 

https://velog.io/@haiseong/Set-Cookie%EB%A1%9C-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%97%90-%EC%BF%A0%ED%82%A4-%EC%A0%80%EC%9E%A5%ED%95%98%EA%B8%B0#set-cookie

 

Set-Cookie로 브라우저에 쿠키 저장하기

Cookie 세션 스토리지, 로컬 스토리지, 등등 웹 브라우저에는 정보를 저장할 수 있는 공간이 있다. 최근에 jwt 인증방식을 위해 쿠키를 구워야 했다. 쿠키는 유저들의 효율적이고 안전한 웹 사용을

velog.io

 

댓글