cookie를 frontend에서 저장하지 않고 backend에서 저장하는 이유부터 알아보자!
왤까?
가장 중요한건 보안때문이다. 보안때매 사용하는거면 별로 안 중요한거면 그냥 넘겨도 되겠네 싶겠는데 별로 안 중요한걸 기록하며 사용하는 일이 많을까 싶다. 일단 내가 저장하려는거는 "토큰"이였다. access token을 cookie에 저장하려고한다. 탈취되거나 조작되면 안 된다. 따라서 코드로 접근해서 저장하고 넣는 과정을 frontend에게 허용한다면 보안 취약점이 될 수 있다.
중요한 정보를 Cookie에 저장하려면 Backend 코드에 의해서 Browser에 저장해줘야한다.!
그렇기 때문에 나는 Spring에서 Cookie를 세팅해줬다.
이 과정에서,,,, 백엔드 개발자도 기본적인 브라우저 동작 과정과 정책을 알고 있어야한다는 점을 깨달았다... 돌고돌고 돌아서 결국 Cookie를 browse에 세팅해줬다. 그 과정을 공유한다!
같은 사이트인가? 말 그대로 같은 출처를 공유하는지 체크하는거고 '같은 출처'의 영역의 정의는 아래의 3가지 옵션에 따라 달라진다.
CORS랑 같은건가??뭐가다르지? 생각해봤다. 사실 처음에 같은 줄 알았다. Site랑 Origin의 체크의 차이이다. Samesite는 도메인을 비교한다. 포트는 상관없다. Origin이랑 다르다.
Site랑 Origin이랑 다르다.
Site는 http.asdf.com일때 asdf.com이다.
그러면 https.asdf.zcxv.com일때 사이트는? zcxv.com이다. com과 같은 public suffix 바로 앞에까지를 포함해서 site라고 한다.
<a>
, GET은 되고 이러한 몇가지 예외가 존재하긴한다.CSRF
Cross-Site Request Fogery 공격은 악의적으로 쿠키탈취를 위한 링크를 심어놓고 클릭을 유도하여 인증정보를 빼서 사용하기 위한 공격이다. 이를 방지할 수 있는게 Samesite다. 왜냐? 다른 도메인을 클릭했을 때 쿠키를 아예 전송할 수 없기 때문이다.! 물론 None일땐 다른 도메인이여도 가능하다. 그래서, None일때는 Secure가 (SSL이 적용된 도메인) 무조건 적용이 되어있어야 애초에 세팅이 가능하다.
그렇다면 위에서 말한 같은 Origin이란? 자꾸 도메인이라는 표현을 써서 헷갈릴 수 있는데(나도 그랬다)
Origin은 Protocol, Host, Port로 구성된다. 세게가 모두 동일해야 같은 Origin이다.
예를들어 React, Spring은 localhost일때 같은 Origin일까? Port가 같지 않으니,다른 Origin이다. 그러나 Samesite는 만족한다.
따라서, React, Spring 개발 환경일때 Spring에서 React 환경의 웹에 쿠키를 넣고 싶다면?
그러나, 다른 Origin이다. 따라서, Origin이 다르면 Cross Origin으로 인해, 브라우저는 쿠키세팅을 막는다.
Protocol인 HTTP를 사용할때만 죽, 코드가 아닌 네트워크 상에서만 쿠키 세팅을 할 수 있도록 설정할 수 있는 옵션이다.
True로 해줘야 XSS(Cross Site Scripting)인 SQL injection같이 악의적으로 사이트에 이상한 스크립트(코드)를 넣어 공격하는거를 방지할 수 있다.
이 옵션을 통해 프론트엔드에서 javascript를 통한 쿠키 탈취를 예방할 수 있게 된다.
그렇다면,네트워크로 접속하는건 어떻게 처리하지? 이거는 CSRF와 관련있다. 위에서 말했듯, CSRF는 다른 사이트로 넘어가며 네트워크상에서 탈취당하는건데 Samesite로 막을 수 있다. 그러나, None일때는? Secure로 막을 수 있다.
HTTPS에서의 통신만 허용하게끔 하는 옵션이다. HTTPS 프로토콜을 사용하는 것은 데이터 암호화하여 통신하는 방법으로, 쿠키 또한 암호화되어 전송돼서 탈취당하더라도 내용을 알 수 없다. 그렇기에, 네트워크 상으로 쿠키가 이동해도 안전하게끔 해주는 옵션이다.
Cookie 하나에 브라우저 지식이 많이 필요했다... 항상 느끼지만 문제를 해결할땐 이론을 파면 되는 것 같다! 그냥 무작정 구글링하지 않고 Cookie 설정 속성값들을 천천히 읽고 이해하니까 문제가 풀렸다! 이래에서 확인해보자!
네트워크상으로 전송은 되는데, 브라우저에 세팅이 안 된다
request cookie에는 잘 들어간다. Network탭에서 Headers에 가보면 Set-Cookie에도 잘 들어가있는걸 확인했다.
서로 다른 Origin이기에 안 되는 것이다. 포트가 다르기에 credential을 true로 바꿔줘야한다.
결론은, withCredentials를 Frontend와 Backend에서 모두 true로 해주니 Cookie설정 지옥에서 빠져나올 수 있었다!
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins(
"http://localhost:3000", // local,
"https://where-qr.com" //dev
)
.allowedMethods("GET", "POST", "PATCH", "DELETE")
.allowedHeaders("*")
.allowCredentials(true);
}
}
그리고 주의할 점은, allowedOrigins를 특정 도메인을 정해줘야지, * 하면 allwCredentials true가 먹히지 않는다는 점이다!
문제해결할때 흐름이 끊기면 안 된다..미루게 된다....! localstorage에서 refresh token을 드디어 cookie에 넣었다.
브라우저 정책! 매우매우 중요하다! Backend에서 브라우저에 뭔가를 세팅하려고한다? 무조건 정책부터 보고시작하자! 그리고 쿠키 옵션들을 완전히 이해하고 시작했으면 문제해결이 빨랐을 것이다.
덕분에 쿠키랑 관련된 브라우저 보안관련 지식에서 마스터했다...^^ HttpOnly는 network 전송만 가능하도록하기에, js와 같은 코드로 발생하는 XSS 방지. 그러면 다른 사이트로 클릭을 유도해서 쿠키를 탈취할 수 있는 것을 막는 것은? CSRF를 막는것인데 -> 이는 Secure를 통해 가능하고 ...등등에 대해서 이해했다.