사용된 기술
프론트 : React(CRA), RTK-Query
백앤드 : Spring
브라우저 환경: Chrome
백앤드 서버 도메인: AWS서버에서 나온 도메인
프론트 서버 도메인: localhost3000
목표
프론트에서 백앤드 서버로 API요청 테스트 해보기
쿠키
쿠키에 관한 삽질 내용을 정리해보자 한다 우리는 카카오 로그인을 사용하려 하였다
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api
카카오의 로그인 방법중 REST API를 사용하였고 간단하게 요약하면
- 유저가 카카오 로그인을 클릭하면 프론트서버가 지정된 URL로 (자세한건 공식문서 참조) 보내 카카오서비스에 로그인을한다
- 로그인을 하면 카카오 서버가 자동으로 설정한 redirect url로 url에 인가코드와 합쳐서 redirect 시킨다.
- 프론트는 이 url을 parsing해서 백앤드로 인가코드 값을 보낸다
- 백앤드는 인가코드를 카카오서버에 토큰을 요청한다
- 카카오 서버에서 토큰을 확인하고 주면 쿠키를 생성해 프론트로 넘겨준다
여기서 문제가 생긴것이 토큰을 확인하고 쿠키를 생성을 잘했지만 프론트로 넘겨주니 에러가 발생한것이다
에러의 서막 Cors Error
cors 에러는 프론트와 백앤드를 한번이라도 했다면 한번쯤 겪어봤을 에러이다 Cross Origin Resource Sharing의 약자로 도메인 및 포트가 다른 곳에서 클라이언트가 요청했기 때문에 보안에러로 일어나는 것이다.
why?
잘 생각해보자 도메인 및 포트가 다른 곳에서 클라이언트가 요청해서 서버를 제어하는데 서버입장에서는 도대체 무엇을 믿고 요청을 받아서 수행한단 말인가? 그게 해커인지 정상적인 사용자인지 어떻게 알까?
해결법
그럼 해결법은 간단하다 내가 신뢰할수 있는 사용자라는것을 증명하면 된다
1. Proxy
proxy는 클라이언트가 서버에 직접 요청을 하기에 문제가되는것이니 직접 요청하지말고 간접적으로 요청하는 방법이다
간단하게 웹팩 개발서버에서 제공하는 Proxy라는 기능이 있다
이것을 사용하게 되면 브라우저는 서버에 요청을 하고 서버는 그대로 백엔드서버에 요청을 하게되고 데이터 또한 같은 방법으로 받게 된다 이는 프록시 서버라는 신뢰하는 출처에서 백엔드에서 오는 것이므로 cors에러가 발생하지 않는다.
2. 응답해더 설정
나는 이 응답해더를 사용해서 해결하였다 응답해더에 'Access Control Allow Origin"를 요청받는 주소(프론트 주소로)설정하면 된다. 이 설정이 된 도메인은 접근을 허용하겠다는 의미이다
물론 나는 프론트여서 설정해 줄게 없었고 백앤드에 요청을 해주면 된다
cors에러는 서버가 아닌 브라우저가 일으키는 에러 이기때문에 백앤드에 reponse header에 이 'Access Control Allow Origin" 설정이 있어야 브라우저가 확인을하고 응답을 받을 수 있다.
이정도는 상황에 맞게 찾아봐서 세팅만 잘해주면 껌이지 생각하고 있었다 하지만 해결되지 않은 오류가 있었다
어 왜 안됨??? Cookie
기분좋게 cors에러를 해결하고 cookie까지 받을수 있도록 header에 credentials 설정하였다
//RTK-Query 문법이다
baseQuery: fetchBaseQuery({
baseUrl: 'aws에 있는 주소',
credentials: 'include',
}),
그리고 테스트를 해봤더니 에러없이 데이터를 잘 받을수 있었다
포스팅 끝...
하지만 무언가가 이상했다 바로 쿠키가 넘겨져서 왔지만 브라우저에 저장되지 않는 것이다. 정삭적으로라면 쿠키는 응답을 받으면 자동으로 브라우저에 저장이 되어야한다. chrome browser의 devtools Application에서 아무리 뒤져봐도 넘어온 쿠키가 없는 것이었다. 처음에는 쿠키설정을 잘못 한것 인줄알고 검색해봤지만 사실은 쿠키를 이해하지 못해서 생긴 상황이였다
Cookie (feat made in hacker)
쿠키에 대해서 조금만 알아보자 먼저 쿠키를 보기전 HTTP 프로토콜에 대해서 봐야한다
HTTP는 stateless로 요청을 보내면 그 요청의 사용자가 누구인지 모른다. 이 말은 즉 내가 로그인을 했었어도 다음 데이터 요청을하면 서버는 누구세용? 한다는 것이다.
그래서 요청자가 누구인지 알게 해주게끔 증명을 해주는 것이 바로 쿠키이다. 이 쿠키는 header에 set-cookie로 설정되어서 넘어온다
이 쿠키가 XSS(Cross-Site Scripting)공격 스니핑(Sniffing) 공격 등등으로 탈취될수 있기때문에 이를 막고자 보안을 설정하는데 이것이 HttpOnly 옵션이다.
HttpOnly 옵션을 설정하게 되면 javascript에서 쿠키로 접근을 할 수 없게된다. 나는 쿠키가 설정이 안되었으니 이 쿠키값을 직접 빼내서 수동으로 저장하게 하려고 하였다 하지만 이는 나 스스로가 쿠키 탈취를 하고있었던 것이였다.
꼭 명심하자 쿠키는 js로 접근해서 빼낼수 없다.
Chrome 정책 변경
이제 다른 방법을 생각해봐야 했다 header에 경고 메세지가 조그만하게 떠있는걸 볼 수 있었다 cross-site를 사용하려면 SameSite none를 설정해 주라는 것이였다
2020년 2월 4일 릴리즈된 구글 크롬(Google Chrome) 80버전부터 새로운 쿠키 정책이 적용되어 Cookie의 SameSite 속성의 기본 값이 "None"에서 "Lax"로 변경되었다.
크롬에서 새로운 쿠키 정책으로 SameSite 속성이 Lax로 변경되었다
속성 | 설명 |
None | same-site를 검증하지 않음 즉 a도메인 에서 b도메인으로 요청을하면 b사이트 쿠키가 붙여져서 감 (단 secure 옵션을 설정해야함) |
Lax | 일부 예외(get 요청, link href, a href)를 제외하고는 strict이랑 같음 (none랑 strict 사이) |
Strict | 쿠키는 도메인이 서로 일치해야만 쿠키를 보냄 |
우리의 경우를 보자 백앤드 서버의 경우에는 aws도메인이고 프론트는 locallhost로 아예 다른 도메인이다 따라서 None 설정으로 바꿔야지만 쿠키가 붙어진다는 것이다.
"아 그럼 none로 바꿔야지 그러면 secure옵션을 true로 바꿔주고....? 어라? https만 가능하다고?????"
이렇게되면 백앤드 서버 프론트앤드 서버를 모두 https로 바꾸어야 한다 이는 손이 매우 많이 가는 작업이고 아직 배포 단계가 아닌 테스트 해볼 목적이기 때문에 매우 난감했다.
해결
처음이 문제였다 결국 이 문제들의 원흉은 도메인이 다르다는 것이다 그러면 도메인을 똑같이 만들어 주면된다
프론트도 aws 서버에 올려서 테스트하면된다.
결과는 성공적이었다 API도 성공적으로 불러와 지고 쿠키도 잘 저장되어있는것을 볼수 있다.
결론
cors 에러부터 쿠키까지 복잡하기만 했던 내용들을 정리할 수 있던 기회였다
하지만 서버에 올려서 테스트 하는 방법은 최선이 아니다 서버올리기까지 빌드와 로딩과 메모리 시간 이 많이 잡아 먹게된다. 이는 굉장히 비효율적이라는 것을 알게되었다 아마 실제로는 테스트코드를 작성해서 테스트를 해보고 어느정도 완성이 되면 테스트 서버에 배포를 해 검증을 해볼거 같다. 테스트 코드를 꼭배우자...
요약
1. cors에러다
2. 해결 :)
3. 그런데 cookie가 저장이 안되네
4. 도메인이 달라서 저장이 안되는거야
5. 이사이에 뻘짓들