[Web] 구글 Chrome SameSite 이슈에 대하여 (크롬 80)

2020.2.4 구글 크롬(Google Chrome) 80버전으로 업데이트되면서 크롬에 새로운 쿠키 정책이 적용되었다. 내용은 Cookie의 SameSite 속성의 기본 값이 "None"에서 "Lax"로 보안등급을 상향 조절하는 것이다.

 

 구글 Chrome SameSite 이슈에 대하여 

SameSite 속성의 기본 값이 "None"에서 "Lax"로 변경되면 각종 문제가 일어날 수 있습니다. 사용자가 사이트를 이용하다가 갑자기 쿠키가 날아가는 경우가 생길 수 있다는 점입니다. 대표적인 예가 로그인 정보입니다. 많은 웹사이트들이 로그인을 한 후 Cookies를 사용해 유저의 신원을 확인하여 페이지를 전환해도 재인증을 하지 않아도 되도록 하고 있습니다. 하지만 SameSite 이슈로 인해 이 쿠키값을 찾지 못한다면 로그인이 되어 있어야 확인할 수 있는 페이지로 전환했을 때 다시 로그인 페이지로 가겠죠.

 

예를 들어 쇼핑 사이트에서 사용자가 구매하고자 하는 물건을 장바구니에 담아 PG(온라인 결제 대행)사를 통해 결제를 했다고 해보겠습니다. 이때 쇼핑몰 사이트와 PG사의 도메인이 서로 다르기 때문에 세션 아이디를 통해 기존의 쿠키값을 찾지 못하여 로그인 쿠키값이 유실되는 경우가 발생할 수 있습니다. 이렇게 된다면 결제가 완료되면 결제 완료 확인 페이지로 가는 것이 아니라 로그인 페이지로 이동하는 현상이 발생할 수 있습니다.

 

왜 SameSite = None에서 Lax로 변경하는가?

SameSite의 기본 설정값을 None에서 Lax로 변경하는 이유는 기본적으로 CSRF(Cross site request forgery)공격을 막기 위함입니다. CSRF란 사이트 간 요청 위조라는 뜻의 웹사이트 취약점 공격 방식 중 하나로, 사용자의 의지와는 관련 없이 공격자가 의도한 행위를 웹사이트에 요청하는 것을 의미합니다. 대표적으로 2008년도에 옥션이 이 공격으로 피해를 입었습니다.

 

SameSite 설정값에 대하여

SameSite에는 None, Lax, Strict라는 3가지의 속성값이 있습니다. 

 

  • None : 동일 사이트와 크로스 사이트 모두에 쿠키 전송이 가능합니다. 이로인해 CSRF의 공격에 취약한 등 보안에 취약점을 가지고 있습니다. 크롬 80 버전부터는 SameSite를 None으로 설정할 경우 쿠키에 암호화된 HTTPS 연결이 필요함을 나타내는 Secure 속성을 함께 넣어주어야 합니다. 즉 SameSite=None; Secure 이렇게 작성해주어야 하고 URL은 HTTPS로 처리되어야 합니다.
  • Strict : Strict로 설정하면 이 값으로 설정된 쿠키는 도메인 자체에서 시작된 요청에서만 전송됩니다. 즉 SameSite에서만 쿠키의 전송을 허용합니다. 가장 제한적인 방식으로 보안에는 완벽하지만 편의성이 떨어지는 방식입니다.
  • Lax : Lax 모드는 기본적으로는 CrossSite 쿠키값 전송을 차단하는 Strict 모드와 동일하지만 몇가지 예외사항 둬 CrossSite임에도 일부 요청 방식으로는 쿠키를 보낼 수도 있습니다. Strict의 방식에서 예외사항을 추가 한 방식이라고 생각하시면 됩니다.

 

Lax방식에서 쿠키값을 전송할 수 있는 경우

//a href 링크
<a href=""></a>

//prerender 링크
<link rel="prerender" href=".."/>

//HTTP GET 메소드
<form method="GET" action="...">

 

 SameSite 이슈가 발생했을 때 대처 방법 

문제 확인

크롬 개발자도구 (F12) -> 상단바의 애플리케이션 -> 좌측 메뉴의 저장용량 -> 쿠키 -> 도메인을 클릭하시면 위와 같이 쿠키값을 볼 수 있는 화면이 나옵니다. 여기서 쿠키 값을 확인해보세요.

 

해결 방법

근본적인 해결책은 아니고 우회책이지만 두 가지 방법이 있습니다. 첫 번째는 SameSite의 설정값을 Lax에서 None으로 강제로 바꿔주는 것이고 두 번째 방법은 크로스 도메인이 일어나는 부분에서는 쿠키값이 필요한 로직을 삭제하거나 중간에 리다이렉트 페이지를 만드는 것입니다.

 

 SameSite Lax -> None 

본래 크롬 80 버전 이전에는 SameSite의 Defualt값이 none이었습니다. 하지만 Lax로 바뀌면서 생기면서 문제가 되는 것이기에 다시 None으로 바꿔주시면 간단하게 문제가 해결됩니다. SameSite 속성을 변경하는 방법은 쿠키 생성하는 시점부터 설정해주거나 필터 등을 이용하여 기존 쿠키에 속성을 추가하는 방법이 있고 Apache나 Nginx같은 HTTP/Proxy 서버를 사용 중이라면 서버 설정을 통해 일괄로 변경하는 방법도 있습니다.

 

JavaScript

document.cookie = "safeCookie1=foo; SameSite=Lax";
document.cookie = "crossCookie=bar; SameSite=None; Secure"

SameSite=None; 으로 설정할때는 뒤에 Secure을 붙여줘야 합니다.

 

Java

response.setHeader("Set-Cookie", "Test1=TestCookieValue1;   Secure;  SameSite=None");
response.addHeader("Set-Cookie", "Test2=TestCookieValue2;   Secure;  SameSite=None");
response.addHeader("Set-Cookie", "Test3=TestCookieValue3;   Secure;  SameSite=None");

Java에서 많이 사용하는 javax.servlet.http.Cookie Class에서는 SameSite 관련 API를 지원하지 않기 때문에 SameSite 속성을 추가하려면 HttpServletResponse의 response 객체에 Set-Cookie 헤더(Header)를 직접 추가해야 합니다.

 

Filter or Interceptor

public class CookieAttributeFilter implements Filter{
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException){
    
    	HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        chain.doFilter(request, response);
        log.info("CookieAttributeFilter");
        addSameSite(HttpServletResponse, "None");
        
    }
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException{
    }
    
    @Override
    public void destroy(){
    }
    
    private void addSameSite(HttpServletResponse response, String sameSite){    
    	Collection<String> headers = response.getHeaders(httpHeaders.SET_COOKIE);
        boolean firstHeader = true;
        for(String header : headers){
            if(firstHeader){
            	response.setHeader(httpHeader.SET_COOKIE, String.format("%s; Secure; %s", header, "SameSite=" + sameSite));
                firstHeader = false;
                continue;
            }
            response.addHeader(HttpHeaders.SET_COOKIE, String.format("%s; Secure; %s", header, "SameSite=" + sameSite));
        }
    }
} 

소스상에서 하나하나 처리가 힘든 경우 필터(Filter)나 인터셉터(Interceptor) 등을 이용하여 response 를 가로채 위의 예제처럼 로직을 통해 생성된 쿠키의 헤더에 Secure; SameSite=None 속성을 추가하여 일괄로 변경하는 것도 가능합니다.

 

Tomcat 설정 (* context.xml)

<context>
  ...
  <CookieProcessor sameSiteCookies="none"/>
</context>

Tomcat WAS 에서 지원하는 Cookie Processor Component를 이용하여 일괄로 쿠키에 대한 속성을 추가할 수 있습니다.

Tomcat의 Cookie Processor Component 레퍼런스

 

WEB Server 설정 [ Proxy / HTTP Server ]

  • Apache Configuration (httpd.conf)
Header always edit Set-Cookie (.*) "$1; Secure; SameSite=None;"
  • Nginx Configuration (nginx.conf)
location / { 
    # your usual config ... 
    # hack, set all cookies to secure, httponly and samesite (strict or lax) 
    proxy_cookie_path / "/; secure; SameSite=None"; }

Apache 또는 Nginx 같은 HTTP 웹서버나 Proxy 서버를 사용중이라면 서버 설정을 통해 유저가 받는 모든 쿠키 속성을 한 번에 변경할 수 있습니다.

소스코드 출처

 

 리다이렉트 페이지 만들기 

SameSite로 인해 쿠키값이 누실되는 문제는 다른 도메인을 갔다가 돌아오는 가장 처음 페이지에서만 발생하는 문제일 수 있습니다. 처음에만 쿠키값을 찾지 못하고 두 번째 페이지로 전환될 때(같은 도메인에서의 전환)는 정상적으로 쿠키를 찾고 있다면 다른 도메인으로 갔다 오는 페이지를 리다이렉트 페이지로 만들어서 문제를 해결하는 방법도 고려해 볼 수 있습니다. 그게 아니라면 위에서 예시로 드린 결제 완료 페이지와 같이 고정적인 페이지라면 그 페이지에서만 로그인 체크를 하지 않고 인입받은 값들만 넣어주는 방식으로 페이지 처리를 할 수도 있겠습니다.

 

댓글

Designed by JB FACTORY