[10분 테코톡] 🌳 나봄의 CORS의 내용을 정리하고, 추가 학습 내용을 덧붙여 작성했습니다!
SOP (Same Origin Policy)
- 다른 출처의 리소스를 사용하는 것을 제한하는 보안 정책
- Origin(출처)란?
- url의 protocol, host, port를 통해 같은 출처인지, 다른 출처인지 판단한다.
- 세 가지가 모두 같아야지만 같은 출처라고 판단한다.
하지만 브라우저마다 다르다. IE는 port를 판단 기준에 넣지 않는다. port가 달라도 동일 출처라고 보는 것이다.
또, 브라우저에서는 String value로 값을 비교하기 때문에 http://localhost:80과 http://127.0.0.1은 같지만 다른 출처라고 판단한다.
- 왜 보안을 위해 이런 방식을 사용해야 할까?
- 다른 출처의 사용자가 스크립트를 이용해 잘못된 요청을 보낼 수도 있다.
- 이 때, 사이트에서 요청이 어느 출처에서 온 것인지 확인을 한다.
- 이 때, 해당 사이트에서 보낸 요청이 아니면 다른 출처이면 Cross Origin이라고 판단한다.
- SOP를 위반하는 잘못된 요청을 보냈을 때, 브라우저에서 먼저 이를 판단해 CORS(Cross-Origin Resource Sharing) 에러를 발생시킨다.
내가 경험한 SOP 위반 상황
이론적으로는 쉽게 이해가 갔는데, 내가 경험한 상황에 적용해 이해하는 게 조금 헷갈렸어서 적어본다.
우테코 레벨2 마지막 미션 1단계에서, 외부에서 호출할 수 있도록 하는 Rest API 어플리케이션을 백엔드 서버에 배포했다.
이 때, 클라이언트에서 백엔드 서버의 REST API에 요청을 보낼 때 SOP를 위반하는 상황이 생긴 것이다.
(나의 로컬에서 브라우저로 REST API의 url을 직접 사용하여 요청을 보내면 당연히 SOP를 위반하지 않는다.)
하지만 클라이언트에서 요청을 보낼 때는 다른 출처(프론트엔드 서버에서 사용자 화면을 배포한 출처)에서 요청을 보낸다.
따라서 서버 출처와 다른 출처(Cross Origin)이므로, SOP를 위반하는 상황이기 때문에 이는 허용할 수 없는 요청으로 에러가 발생한다.
CORS (Cross-Origin Resource Sharing)
- 추가 HTTP 헤더를 사용하여,
한 **출처**에서 실행중인 웹 애플리케이션
이다른 **출처**의 선택한 자원
에 접근할 수 있는 권한을 부여하도록브라우저
에 알려주는 메커니즘 - CORS 헤더를 활용해 SOP 위반 여부를 판단, 서버가 실제 요청을 허용할지 확인하도록 한다.
- CORS 요청의 종류는 아래와 같다.
- 단순 요청 Simple Request
- 바로 GET 요청을 보내면서 Cross Origin 여부를 확인
- 일부 메서드, Content-Type, 일부 허용 헤더 에서만 가능하다
- 바로 GET 요청을 보냈을 때, 응답은 200 OK로 보내면서
Access-Control-Allow-Origin
값을 전달한다.- 현재 보낸 요청의 Origin이 허가하는 Origin에 해당되지 않으면 Cross Origin 에러가 터진다.
- 바로 GET 요청을 보내면서 Cross Origin 여부를 확인
- 프리플라이트 요청 Preflight Request
- 본 요청을 보내기 전에, Request Method를 OPTIONS로 보낸다. ⇒ 사전확인 작업
- 사전 확인 작업이란?
- OPTIONS 메서드를 통해 다른 도메인의 리소스에 요청이 가능한지 확인한다.
- 사전 확인 요청에 대한 응답을 받아서, 요청이 가능하다는 걸 알게 되면 실제 요청을 보낸다.
- 사전 확인 시 물어보는 것
- 요청 출처
Origin
- 실제 요청으로 가능한 메서드
Access-Control-Request-Method
- 실제 요청에 보낼 수 있는 추가 헤더
Access-Control-Request-Headers
- 요청 출처
- 인증정보 포함 요청 Credentialed Request
- 인증 관련 헤더를 포함할 때 사용하는 요청
- CORS 요청에서는 개인정보 보호를 위해 쿠키를 전송하지 않지만, 추가적인 헤더를 설정하면 쿠키를 주고받을 수 있다.
- 클라이언트 측 :
credentials
속성 값을 include로 설정 - 서버 측 :
Access-Control-Allow-Credentials
를 true 로 설정- 이 때
Access-Control-Allow-Origin: \*
으로 모든 것을 허용하면 안된다. 에러가 터진다. 정확한 Origin을 줘야 한다.
- 이 때
- 참고 링크
- 클라이언트 측 :
- 같은 요청에 대하여 매번 두 번의 요청-응답이 이루어지는 것(자원낭비)을 방지하기 위해 브라우저는 Preflight 응답에 대해 캐싱해두고, 똑같은 요청을 보낼 때는 바로 요청을 보낸다.
- 왜 단순 요청으로 한 번만 보내도 되는데 Preflight 요청으로 두 번 보낼까?
CORS에 대해 아무 것도 모르는 서버를 위해서. CORS에 대해 모르는 서버는 ALLOW-ORIGIN 문제를 모른 채로 응답을 하고, 브라우저에서 CORS 에러가 터지는 것이다. 예를 들어 DB에 데이터를 Delete하는 요청이었다면, 일단 데이터를 다 지운 뒤 CORS 에러가 터지게 된다.
CORS spec이 생기기 이전에 만들어진 서버들은 브라우저의 SOP request만 가능하다는 가정하에 만들어졌다. 그런데 Cross-Site Request가 가능하게 되었고, 기존의 서버들은 CORS에 보안적으로 대응할 수 없게 되었다. 이런 서버들을 보호하기 위해 Preflight Request가 생겼다.
CORS 대응 방법
- 프론트 프록시 서버 설정
- 프론트 서버에서 브라우저의 ORIGIN을 서버의 ORIGIN과 같도록 변경해준다.
- 직접 헤더에 설정해주기
- 가능하나, 스프링 부트를 통해 편하게 할 수 있는데 굳이 그렇게 할 필요가 있을까?
- 스프링 부트를 이용하기
- Controller에 @CrossOrigin 어노테이션 적용
- 전역적으로 설정하고 싶다면 WebMvcConfigurer 또는 Filter 사용
미션에서는 3번 방식으로 문제를 해결하였다.
굳이 프론트에서 프록시 설정을 해주기보다는,
Cross Origin을 허용하는 출처를 서버에서 지정하고, 알고 있는 것이 적절하다고 생각했기 때문이다.
쉽게 CORS 에러 확인하기!
그럼 내가 설정해둔 CORS 대응 방식이 제대로 작동하는지 확인하려면 매번 클라이언트에서 요청을 보내봐야 할까?
이 사이트에서는 편리하게 CORS 요청을 보내보고 에러가 발생하는지 확인할 수 있다.
http://test-cors.org/
'공부 > Web' 카테고리의 다른 글
[웹] HTTP 기초 용어 정리 (0) | 2023.05.14 |
---|