본문 바로가기
내가 보는 개발 공부/Web

다른 도메인을 경유하는 경우의 쿠키

by JeeGAe 2025. 4. 24.

회원가입 중 다른 도메인을 팝업으로 띄워 거기서 정보를 가져오는 로직이 있었는데 그 경우 쿠키에 있는 jsessionid가 바뀌는 현상이 있었고 그로인해 세션이 바뀌어 이전 세션의 정보를 가져올수 없는 상황이었다.

 

src/main/webapp/META-INF/context.xml

<Context>
    <CookieProcessor sameSiteCookies="lax" />
</Context>

samesite 을 lax로 설정해두었는데 이렇게 하면 다른 도메인을 경유하는 경우 쿠키가 전달되지 않아 새로운 session을 생성하면서 쿠키에 새로 jsessionid가 생성되는 듯 하다. 이러면서 csrf문제도 발생했다. (처음에는 단순히 csrf문제로 생각했었다.)

 

그래서 해당 페이지에서만 lax를 풀고 빈값으로 두는 방법으로도 했었지만 그렇게 하니 될때도 있고 안될때도 있고 그랬다.

 

찾아보던중 samesite는 none으로 두고 secure 설정을 주면 된다고 하여 했더니 해결되었다.

 

1) web.xml 에서 설정하기

애플리케이션(WEB-INF/web.xml) 또는 전역($TOMCAT_HOME/conf/web.xml)에 아래를 추가하세요.

<session-config>
  <cookie-config>
    <!-- HttpOnly 설정 (JavaScript 접근 차단) -->
    <http-only>true</http-only>
    <!-- Secure 설정 (HTTPS 로만 전송) -->
    <secure>true</secure>
  </cookie-config>
</session-config>
 

이렇게 하면 톰캣이 발급하는 모든 세션 쿠키에 ; Secure(및 ; HttpOnly) 를 자동으로 붙여 줍니다.

이렇게하고 

 

<Context>
    <CookieProcessor sameSiteCookies="none" />
</Context>

위에 꺼를 이렇게 바꾸고 했더니 해결되었다.

 

 

블로그 내용

SameSite 및 Secure 속성을 JSESSIONID 쿠키로 설정하는 방법 물어보다

1. 질문(문제점):

Spring Boot 웹 애플리케이션(Spring boot 버전 2.0.3.RELEASE)이 있고 Apache Tomcat 8.5.5 서버에서 실행 중입니다.

최근 구글 크롬에서 시행한 Security 정책(80.0 이후 출시 SameSite)에 따라 CSRF 대신 Cross-site 쿠키에 보다 안전한 방식으로 접근할 수 있도록 새로운 속성을 적용해 줄 것을 요청하고 있다. 관련 작업을 수행한 적이 없고 Chrome이 SameSite=Lax자사 쿠키에 대한 기본값을 설정했기 때문에 타사 서비스 통합 중 하나가 타사 서비스 통합에 실패합니다 SameSite=Lax. POST요청 에서 응답이 옵니다 (절차가 완료되면 요청 과 함께 타사 서비스 리디렉션POST ). 거기에 Tomcat이 세션을 찾을 수 없으므로 새 항목을 추가합니다.JSESSIONID(새 세션과 함께 이전 세션이 종료됨) URL 끝에 있습니다. JSESSIONID따라서 Spring은 새 추가 에 의해 도입된 세미콜론이 포함된 URL을 거부합니다 .

그래서 JSESSIONID쿠키 속성( SameSite=None; Secure)을 변경하고 WebFilters를 비롯한 여러 방법으로 시도해야 합니다. Stackoverflow에서 동일한 질문과 답변을 보았고 대부분 시도했지만 아무데도 없었습니다.

누군가 Spring Boot에서 해당 헤더를 변경하는 솔루션을 제안할 수 있습니까?

2. 해결방안:

나는 전에 같은 상황에 있었다. 클래스 SameSite에 같은 것이 없으므로 추가할 수 없습니다.javax.servlet.http.Cookie

1부: 그래서 내가 한 것은 필요한 제3자 요청만 가로채는 필터를 작성하는 것입니다.

public class CustomFilter implements Filter {

    private static final String THIRD_PARTY_URI = "/third/party/uri";


    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        if(THIRD_PARTY_URI.equals(request.getRequestURI())) {
            chain.doFilter(request, new CustomHttpServletResponseWrapper(response));
        } else {
            chain.doFilter(request, response);
        }
    }
enter code here
    // ... init destroy methods here
    
}

파트 2: 쿠키는 Set-Cookie응답 헤더로 전송됩니다. 따라서 이것은 메서드를 CustomHttpServletResponseWrapper재정의하고 addCookie필요한 쿠키인지 확인합니다( JSESSIONID). 쿠키에 추가하는 대신 속성 이 있는 응답 헤더 Set-Cookie에 직접 추가합니다.SameSite=None

public class CustomHttpServletResponseWrapper extends HttpServletResponseWrapper {

    public CustomHttpServletResponseWrapper(HttpServletResponse response) {
        super(response);
    }

    @Override
    public void addCookie(Cookie cookie) {
        if ("JSESSIONID".equals(cookie.getName())) {
            super.addHeader("Set-Cookie", getCookieValue(cookie));
        } else {
            super.addCookie(cookie);
        }
    }

    private String getCookieValue(Cookie cookie) {

        StringBuilder builder = new StringBuilder();
        builder.append(cookie.getName()).append('=').append(cookie.getValue());
        builder.append(";Path=").append(cookie.getPath());
        if (cookie.isHttpOnly()) {
            builder.append(";HttpOnly");
        }
        if (cookie.getSecure()) {
            builder.append(";Secure");
        }
        // here you can append other attributes like domain / max-age etc.
        builder.append(";SameSite=None");
        return builder.toString();
    }
}