ÃֽŠ°Ô½Ã±Û(JAVA)
2021.04.29 / 14:43

Cookie SameSite ¼³Á¤Çϱâ (Chrome 80 ÄíÅ° À̽´)

ÇϾá¼Ò
Ãßõ ¼ö 285
20³â 2¿ù 4ÀÏ ¸±¸®ÁîµÈ ±¸±Û Å©·Ò(Google Chrome)80¹öÀüºÎÅÍ »õ·Î¿î ÄíÅ° Á¤Ã¥ÀÌ Àû¿ë µÇ¾î CookieÀÇ  SameSite ¼Ó¼ºÀÇ ±âº»°ªÀÌ "None"¿¡¼­ "Lax"·Î º¯°æµÇ¾ú½À´Ï´Ù.
 
SameSite ¸¦ None À¸·Î ¼³Á¤ÇÒ °æ¿ì ¸ðµç µµ¸ÞÀο¡¼­ ÄíÅ°¸¦ Àü¼ÛÇÏ°í »ç¿ëÇÒ ¼ö ÀÖÁö¸¸  »ç¿ëÀÚ°¡ »çÀÌÆ® °£ ¿äû À§Á¶(CSRF - Cross-site request forgery) ¹× ÀǵµÇÏÁö ¾ÊÀº Á¤º¸ À¯Ãâ¿¡ Ãë¾àÇØÁú °¡´É¼ºÀÌ ÀÖ½À´Ï´Ù. ÀÌ·¯ÇÑ Ãë¾àÁ¡À» ¹æÁöÇϱâ À§ÇØ Áö±Ý±îÁö´Â º°µµÀÇ SameSite ¼Ó¼º ¸í½Ã ¾øÀÌ ÄíÅ°¸¦ »ý¼ºÇßÀ» ¶§ "SameSite=None" À¸·Î ¼³Á¤ÇÑ °Í°ú µ¿ÀÏÇÏ°Ô µ¿ÀÛ ÇßÁö¸¸ Chrome80 ¹öÀü ÀÌÈÄ¿¡´Â SameSite ¼Ó¼º ¼³Á¤ÀÌ ¾ø´Â ÄíÅ°´Â "SameSite=Lax" ·Î ¸í½ÃÇÑ °Í°ú µ¿ÀÏÇÏ°Ô µ¿ÀÛÇÑ´Ù´Â °ÍÀÔ´Ï´Ù.
 
±âº» º¸¾È ¼³Á¤ÀÌ ¿Ã¶ó °¨¿¡ µû¶ó °áÁ¦(PG)³ª ÀÎÁõ ¸ðµâ µîÀÇ ½áµåÆÄƼ ½Ã½ºÅÛ°ú ¿¬°èµÈ ¼­ºñ½º°¡ Á¤»óÀûÀ¸·Î µ¿ÀÛÇÏÁö ¾ÊÀ»  ¼ö À־ÞÈ÷ °ü·Ã ³»¿ëÀ» ã¾Æº¸½Å ºÐµéµµ ¸¹À¸½Ç °Å¶ó »ý°¢µË´Ï´Ù. »ç½Ç °³¹ßÀںеéÀÌ ÄíÅ°¸¦ »ý¼ºÇÒ¶§ Ư¼öÇÑ °æ¿ì°¡ ¾Æ´Ï¸é SameSite¼Ó¼ºÀ» ¸í½ÃÀûÀ¸·Î ¼³Á¤ÇÏ´Â °æ¿ì°¡ ¸¹Áö ¾ÊÁÒ. ¸¹ÀÌ »ç¿ëÇÏ´Â JavaÀÇ Cookie (javax.servlet.http.Cookie) Class¿¡¼­´Â SameSite °ü·Ã API¸¦ Áö¿øÇÏÁöµµ ¾Ê¾Æ ÇØ´ç¼Ó¼ºÀ» ¸ð¸£½Ã´Â ºÐµéµµ ÀÖÀ¸¼ÌÀ» °Í °°½À´Ï´Ù. 
 
ÀÌÈÄ Firefox, Edge µî ´Ù¸¥ ºê¶ó¿ìÀúµµ Chrome °ú µ¿ÀÏÇÑ ¼³Á¤À¸·Î ±âº»°ªÀ» º¯°æÇÑ´Ù°í ÇÏ´Ï ÀÌÂü¿¡ ³»¿ëÀ» ¾Ë¾ÆµÎ½Ã¸é ÁÁÀ» °Í °°³×¿ä.
 
| SameSite 
 
CookieÀÇ SameSite ¼Ó¼ºÀº ¼­·Î ´Ù¸¥ µµ¸ÞÀΰ£ÀÇ ÄíÅ° Àü¼Û¿¡ ´ëÇÑ º¸¾ÈÀ» ¼³Á¤ÇÕ´Ï´Ù.
A cookie with "SameSite=Strict" will only be sent with a same-site request.
A cookie with "SameSite=Lax" will be sent with a same-site request, or a cross-site top-level navigation with a "safe" HTTP method.
A cookie with "SameSite=None" will be sent with both same-site and cross-site requests.
À§¿Í °°ÀÌ "None"Àº µ¿ÀÏ »çÀÌÆ®°ú Å©·Î½º »çÀÌÆ®¿¡ ¸ðµÎ ÄíÅ° Àü¼ÛÀÌ °¡´ÉÇÕ´Ï´Ù. ±×¸®°í "Strict"·Î ¼³Á¤ÇÒ °æ¿ì ¼­·Î ´Ù¸¥ µµ¸ÞÀο¡¼­´Â ¾Æ¿¹ Àü¼ÛÀÌ ºÒ°¡´ÉÇØ Áö±â ¶§¹®¿¡ CSRF¸¦ 100% ¹æÁöÇÒ ¼ö ÀÖÀ¸³ª »ç¿ëÀÚ ÆíÀǼºÀ» ¸¹ÀÌ ÇØÄ¡°Ô µË´Ï´Ù. ±×·¡¼­ Strict ¼³Á¤¿¡ ÀϺΠ ¿¹¿Ü( HTTP get method / a href / link href )¸¦ µÎ¾î Àû¿ëµÇ´Â ¼³Á¤ÀÌ À̹ø¿¡ ±âº»°ªÀ¸·Î º¯°æµÇ´Â "LaxÀÔ´Ï´Ù. 
 
ºê¶ó¿ìÀú¿¡¼­ ±âº» ¼³Á¤À» º¯°æÇÑ °ÍÀº Å©·Î½º µµ¸ÞÀΰ£ Áß¿äÇÑ Á¤º¸ À¯Áö´Â CSRF °¡´É¼ºÀÌ ÀÖ´Â ÄíÅ°°¡ ¾Æ´Ñ ´Ù¸¥ ¾ÈÀüÇÑ ¹æ½ÄÀ¸·Î Çϱ⸦ ±ÇÀåÇϱ⠶§¹®ÀÔ´Ï´Ù. Á¦¾ÈÇÏ´Â ´ë·Î Lax ¼³Á¤¿¡¼­µµ ¹®Á¦ ¾ø°Ô²û ÄíÅ°¿¡ ´ëÇÑ ÀÇÁ¸¼ºÀ» ³·Ãß´Â °ÍÀÌ ±ÇÀå µÇÁö¸¸ ¹Ù·Î ¼öÁ¤°³¹ßÀÌ Èûµç °æ¿ì´Â ÄíÅ°ÀÇ SameSite¼³Á¤À» ±âÁ¸ÀÇ ±âº»°ªÀ̾ú´ø NoneÀ¸·Î ¼³Á¤ÇÏ¿© Àӽ÷ΠÇØ°á ÇÒ ¼ö ÀÖ½À´Ï´Ù.
 
| SameSite ¼³Á¤Çϱâ
 
SameSite ¼Ó¼ºÀ» º¯°æÇÏ´Â ¹æ¹ýÀº ÄíÅ° »ý¼ºÇÏ´Â ½ÃÁ¡ºÎÅÍ ¼³Á¤ÇØ Áְųª ÇÊÅÍ µîÀ» ÀÌ¿ëÇÏ¿© ±âÁ¸ ÄíÅ°¿¡ ¼Ó¼ºÀ» Ãß°¡ÇÏ´Â ¹æ¹ýÀÌ ÀÖ°í Apache ¶Ç´Â Nginx °°Àº HTTP / Proxy ¼­¹ö¸¦ »ç¿ëÁßÀ̶ó¸é ¼­¹ö ¼³Á¤À» ÅëÇØ ÀÏ°ý·Î º¯°æÇÏ´Â °Íµµ °¡´ÉÇÕ´Ï´Ù.

| 1. JavaScript
document.cookie = "safeCookie1=foo; SameSite=Lax"; 
document.cookie = "safeCookie2=foo";  
document.cookie = "crossCookie=bar; SameSite=None; Secure";
SameSite ¼Ó¼ºÀ» ¸í½ÃÇÑ safeCookie1¿Í ¸í½ÃÇÏÁö ¾ÊÀº  safeCookie2´Â Å©·Ò80 ÀÌ»óºÎÅÍ µ¿ÀÏÇÏ°Ô µ¿ÀÛÇÕ´Ï´Ù. (Default Lax Àû¿ë)
 
ÁÖÀÇÇÏ¼Å¾ß ÇÒ Á¡Àº SameSite ¼Ó¼ºÀ»  NoneÀ¸·Î ¼³Á¤ÇÒ °æ¿ì  Secure ¼Ó¼ºÀ» ÇÔ²² Ãß°¡ÇØ ÁÖ¼Å¾ß ÇÑ´Ù´Â Á¡ÀÔ´Ï´Ù. Secure ¼Ó¼ºÀÌ Ãß°¡µÈ ÄíÅ°´Â HTTPS ÇÁ·ÎÅäÄÝ¿¡¼­¸¸ Àü¼ÛÀÌ °¡´ÉÇϸç SameSite°¡ NoneÀÌÁö¸¸ Secure ¼Ó¼ºÀÌ ¾øÀ» °æ¿ì ºê¶ó¿ìÀú¿¡¼­´Â ¾Æ·¡ÀÇ °æ°í¸Þ½ÃÁö¿Í ÇÔ²² ÇØ´ç ÄíÅ°¸¦ Àû¿ëÇÏÁö ¾Ê½À´Ï´Ù.

This set-cookie had the "SameStie=None" attribute but did not have the "Secure" attribute. which is required in order to use "SameSite=None" 
 
| 2. Java Application
 
Java ¿¡¼­ ¸¹ÀÌ »ç¿ëÇϴ javax.servlet.http.Cookie Class¿¡¼­´Â SameSite °ü·Ã API¸¦ Áö¿øÇÏÁö ¾Ê±â¶§¹®¿¡  SameSite ¼Ó¼ºÀ» Ãß°¡ÇÏ·Á¸é HttpServletResponse ÀÇ response °´Ã¼¿¡  Set-Cookie Çì´õ(Header)¸¦ Á÷Á¢ Ãß°¡ÇØ ÁÖ¼Å¾ß ÇÕ´Ï´Ù.
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");
ÁÖÀÇ ÇÏ¼Å¾ß ÇÒÁ¡Àº setHeader ¸¦ ÅëÇØ Set-Cookie Çì´õ¸¦ óÀ½ Ãß°¡ÇÑ µÚ¿¡ setHeader¸¦ ´Ù½Ã »ç¿ëÇÒ °æ¿ì µ¿ÀÏÀ̸§ÀÇ Çì´õ°¡ ¿À¹ö¶óÀÌµå µÇ±â ¶§¹®¿¡ ù Ãß°¡ ÀÌÈÄ¿¡´Â addHeader¸¦ ÅëÇØ Ãß°¡ ÇØÁÖ¼Å¾ß ÇÕ´Ï´Ù. 
 
¸¸¾à Spring Core 5.0 ÀÌ»ó ¹öÀüÀ» »ç¿ëÁßÀ̽öó¸é  org.springframework.http.ResponseCookie ClassÀÇ API ¸¦ »ç¿ëÇÏ¿© Á¶±Ý ´õ ½±°Ô 󸮰¡ °¡´ÉÇÕ´Ï´Ù.
ResponseCookie cookie = ResponseCookie.from("sameSiteCookie", "sameSiteCookieValue")
            .domain("ifuwanna.tistory.com") 
            .sameSite("None")
            .secure(true)
            .path("/")
            .build();
response.addHeader('Set-Cookie', cookie.toString());
 
| 3. Filter or Interceptor 
 
À§Ã³·³ ¼Ò½º»ó¿¡¼­ ÇϳªÇϳª 󸮰¡ Èûµç °æ¿ì ÇÊÅÍ(Filter)³ª ÀÎÅͼÁÅÍ(Interceptor) µîÀ» ÀÌ¿ëÇÏ¿© response ¸¦ °¡·Îä ¾Æ·¡ ·ÎÁ÷À» ÅëÇØ »ý¼ºµÈ ÄíÅ°ÀÇ Çì´õ¿¡ Secure; SameSite=None ¼Ó¼ºÀ» Ãß°¡ÇÏ¿© ÀÏ°ý·Î º¯°æÇÏ´Â °Íµµ °¡´ÉÇÕ´Ï´Ù.
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 {
		// TODO Auto-generated method stub
	}
	@Override
	public void destroy() {
		// TODO Auto-generated method stub	
	}	
	
        private void addSameSite(HttpServletResponse response, String sameSite) {
    	
        Collection<String> headers = response.getHeaders(HttpHeaders.SET_COOKIE);
        boolean firstHeader = true;
        for (String header : headers) { // there can be multiple Set-Cookie attributes
            if (firstHeader) {
                response.setHeader(HttpHeaders.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));
        }
        
    }
	
}

| 4. Tomcat ¼³Á¤
 
Tomcat WAS ¿¡¼­ Áö¿øÇϴ Cookie Processor Component ¸¦ ÀÌ¿ëÇÏ¿© ÀÏ°ý·Î ÄíÅ°¿¡ ´ëÇÑ ¼Ó¼ºÀ» Ãß°¡ ÇÒ ¼ö ÀÖ½À´Ï´Ù.
* context.xml
<Context>
    ...
    <CookieProcessor sameSiteCookies="none"/>
</Context>
TomcatÀÇ Cookie Processor Component ÀÚ¼¼ÇÑ ·¹ÆÛ·±½º´Â ¾Æ·¡ document¸¦ Âü°íÇØ ÁÖ¼¼¿ä!
 
| 5. WEB Server ¼³Á¤ [ Proxy / HTTP Server ]
 
Apache ¶Ç´Â Nginx °°Àº HTTP À¥¼­¹ö³ª Proxy ¼­¹ö¸¦ »ç¿ëÁßÀ̶ó¸é ¼­¹ö ¼³Á¤À» ÅëÇØ À¯Àú°¡ ¹Þ´Â ¸ðµç ÄíÅ° ¼Ó¼ºÀ» ÇÑ ¹ø¿¡ º¯°æ ÇÒ ¼ö ÀÖ½À´Ï´Ù.
 
Apache Configuration
Header always edit Set-Cookie (.*) "$1; Secure; SameSite=None;"
Nginx configuration
location / {
    # your usual config ...
    # hack, set all cookies to secure, httponly and samesite (strict or lax)
    proxy_cookie_path / "/; secure; SameSite=None";
}
 
Reference
https://github.com/GoogleChromeLabs/samesite-examples
https://tomcat.apache.org/tomcat-8.5-doc/config/cookie-processor.html

 



Ãâó: https://ifuwanna.tistory.com/223 [IfUwanna IT]