오늘 정리할 내용은 CORS이다.
그 전까지 CORS가 보안 관련된 용어라는 것을 알고 있었지만
진짜 무슨 의미인지, 왜 중요한지는 몰랐다.
그래서 오늘 검색을 해봤는데
아주 좋으신 분이 잘 정리한 블로그가 있었다.
그거 좀 보고 정리하려고 한다.
그런데 너무 정리를 잘하셔서..
CORS란?
먼저 CORS라는 단어 자체를 한 번 풀어보자.
Cross-Origin-Resource-Sharing이란 뜻이다.
오오.. 딱 봐도 어려워 보인다 ^__^..
cors는 하나의 정책이다.
cors 정책을 위반하게 될 경우 아래처럼 에러가 뜨게 된다.
우리는 무엇을 잘못했길래 이런 에러가 뜨는 것일까?
감옥가나 ㅠㅠ.
CORS는 우리가 작업하고 있는 서버의 위치가 아닌
다른 서버에서 데이터 요청을 할 경우
CORS 정책을 위반하게 된다.
그러면 어떻게 우리가 작업하는 서버의 위치를 알 수 있을까?
Origin
우리가 작업하고 있는 서버의 위치는 URL을 통해 구분을 한다.
이를 출처(Origin)이라고 한다.
원래는 동일한 출처에서만 리소스를 공유할 수 있다. 이는 SOP 정책이라고 한다.
하지만 세상 사는 일이 이쪽도 갔다 저쪽도 갈 수 있기 때문에
다른 출처를 이용해야 할 경우도 많다.
지금 우리가 다른 블로그의 내용을 이용해서 내 블로그를 작성하는 것처럼!
그래서 CORS정책이 나온 것이다.
위의 이미지가 너무 좋아서 가져왔다. 여기서 Protocal, Host, Port가 모두 동일 해야지 같은 Origin 이라고 인식을 한다.
여기서 Port는 생략이 가능하다!
하지만 Port가 포함되어 있으면 포트까지 모두 일치해야 한다.
만약 여러분들의 Origin이 궁금하다면
1
console.log(location.origin);
를 하면 알 수 있다.
추가로, 포트를 무시하는 브라우저는 Internet Explorer밖에 없다고 한다.
버리자!
크롬이 짱짱맨이다.
출처가 다르다고 해서 우리의 코드가 작동이 안 하는 것은 아니다.
서버와 요청과 응답을 하고나서
CORS가 위반되면 브라우저에서 판단하고 해당 데이터를 버리게 된다.
그러니까 로직에는 문제가 없고,
정상적으로 데이터를 받았다고 떠도
브라우저가 거절하는 거니까 기억해두자!!
SOP(Same-Origin-Policy)
위에 잠깐 언급한 SOP도 간략하게 알아보자.
SOP는 원래 동일한 출처에서만 리소스를 공유해야 한다는 정책이다.
그러나 예외가 있기 때문에 만든 것이 CORS.
SOP정책을 위반하지 않아야 하며, 예외 상황에서는 CORS 정책을 지켜야 한다.
아직 클라이언트 어플리케이션의 보안이 얼마나 취약한지 깊게 알지는 못한다.
그러나 개발자 도구를 통해 볼 수 있는 DOM 코드를 볼 수 있다는 것만으로
이미 보안이 취약하다고 한다.
그러다 보니 다른 출처와 통신하는 것을 자유롭게 허용하면
CSRF나 XSS와 같은 공격에 당하기 쉬워진다고 한다.
CSRF나 XSS에 대해서는 나중에 더 공부해보자.
CORS 정책 사용법
우리가 서버에 요청을 하면
요청 헤더에 아래 그림과 같이 출처가 가게 된다.
그러면 서버에서는 이에 대한 응답으로
Access-Control-Allow-Origin에 허용된 출처인지 보여준다.
브라우저는 이 둘을 비교하고 같은 경우에는 유효한 응답이라고 판단하여
데이터를 보여준다.
Access-Control-Allow-Origin를 해서 모든 곳에 허용할 수는 있지만
좋지는 않다!
이것이 가장 기본적인 CORS이다.
CORS 요청의 종류는 몇 가지가 있다.
Preflight Request
Preflight Request는 서버에 요청을 보내기 전에
먼저 예비 요청을 보내고, 서버도 예비 요청에 응답을 한 다음에
진짜 요청을 보내는 방식이다.
Access-Control-Allow-Methods라는 녀석이 있는데
여기에 GET, POST 등을 적어 미리 서어베 알려주게 된다.
Simple Request
이는 예비 요청 없이 바로 본 요청을 보내는 것이다.
Preflight Requset랑 다른 점은 예비의 유무이다.
Credentialed Request
우리가 요청을 할 때 기본적인 데이터 말고 인증과 관련된 것도 요청할 수 있다.
그러면 우리는 요청을 보낼 때 인증과 관련된 정보를 담아서 인증을 해야 하는데
이때 설정하는 것이 아래다.
1
credentials: 'includes';
이렇게 하면 출처가 동일해도 인증 정보가 담겨있기 때문에
인증 정보가 담겨 있을 때는 CORS 정책이 조금 까다로워 진다.
Access-Control-Allow-Origin 에 속성을 사용할 수 없게 되며
응답 헤더에는 Access-Control-Allow-Credentials: true가 꼭 있어야 한다.
그 외의 속성들
Access-Control-Allow-Credentials
이 속성의 값을 Includes로 해놓으면 브라우저에서 응답을 프론트엔드 코드에 노출할지 알려준다.
CORS는 기본적으로 쿠키를 요청으로 보낼 수 없도록 막고 있다.
우리가 같은 origin 에서 통신을 하면 알아서 cookie 정보가
request header에 들어가게 된다.
하지만 다른 통신에서는 이 설정을 해줘야 한다.
그렇기 위해 해주는 작업이 2가지라고 한다.
- withCredentials:true => 프론트
- Access-Control-Allow-Credentials:true =>백
이제
request header에 쿠키를 넣을 수 있게 된다.
만약 설정을 안 해주거나 false라면
요청을 서버에 보낼 때 credentials 정보를 보내지 않는다.
조금 알아봤는데 겉핥기로만 알아봐서
나도 부족한 점이 참 많다.
이런 내용들을 다 공부하는 사람들 칭찬해.. 대단해..
그 외에도 CORS 정책을 우회하는 방법 등이 있지만
거기까지는 정리하지 않았다.
정리하자면
앞으로 CORS에러가 뜨면
- Access-Control-Allow-Origin을 확인하자.
- 쿠키나 인증 데이터가 필요하면 withCredentials:true 하자.
- 2번 방법을 쓸 때 Access-Control-Allow-Origin의 값은 정확히 명시하자.
끝!!