CORS란
- CORS(Cross-Origin Resource Sharing)는 출처가 다른 자원들을 공유한다는 뜻.
- 다른 출처에 있는 자원을 요청하면, 이를 교차 출처 요청이라고 한다.
- 기본적으로 동일한 출처의 리소스와 상호작용 하도록 허용.
- 브라우저의 Web API인 XMLHttpRequest와 Fetch 역시 동일 출처 정책을 따른다. 그래서 다른 출처에서 리소스를 가져오기 위해서는 그 출처에서 CORS 헤더를 포함한 응답을 반환해야 한다.
what is 출처(Origin)?
- 어떤 웹 콘텐츠에 접근하려고 할 때 사용하는 URL의 프로토콜, 도메인, 포트번호를 Origin이라고 함
- 따라서 프로토콜+호스트+포트가 같으면 동일 출처라고 한다.
* 동일 출처 예시
*다른 출처 예시
http://example.com:80
http://example.comHTTP 기본 Port인 80번이 생략되어 있으므로 동일 출처이다. http://example.com/app1/index.html
http://example.com/app2/index.html오리진이 같으며, Path부터 다르므로 동일 출처이다.
http://example.com/app1
https://example.com/app2프로토콜이 다르다. http://example.com
http://www.example.com
http://myapp.example.comHost가 다르다. http://example.com
http://example.com:8080포트가 다르다.
다른 출처 요청일 경우, CORS 정책에 준수하여 요청해야만 정상적으로 응답을 받을 수 있다.
다른 출처 요청 정책
다른 출처 요청 정책은 3가지가 있다.
- 단순 요청(Simple Request)
- 프리플라이트 요청(Preflighted Request)
- 인증정보요청(Credential Request)
1. 단순 요청(Simple Request)
- GET, HEAD, POST 요청만 가능
- Accept, Accept-Language, Content-Language, Content-Type과 같은 CORS 안전 리스트 헤더 혹은 User-Agent 헤더만 포함가능
- Content-Type 헤더는 아래 세 종류만 가능
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- ReadableStream 객체가 사용되지 않음
- XMLHttpRequest 객체를 사용하여 요청하면, 요청에서 사용된 XMLHttpRequest.upload에 의해 반환되는 객체에 어떠한 이벤트 리스너도 등록되지 않는다.
브라우저는 다른 출처에 자신의 주소를 origin에 담아서 요청을 보낸다. 서버는 요청을 확인하고 다른 출처 주소에 접근이 가능하다는 access-control-allow-origin에 해당 주소를 담아서 결과를 리턴한다.
access-control-allow-origin
액세스를 요청하는 애플리케이션 또는 소스가 응답 콘텐츠에 액세스 할 수 있는지 여부를 명시하는 HTTP 응답 헤더이다.
모든 출처를 허용과 특정 출처 허용으로 나뉜다.
모든 출처 허용은 값에 *를 넣어준다.
특정 출처 허용은 값에 특정 주소를 넣어준다.
2. 프리 플라이트(Preflight Request)
- 프리 플라이트는 OPTIONS 메서드로 HTTP 요청을 미리 보내 실제 요청이 전송하기에 안전한지 확인.
- 다른 출처 요청이 유저 데이터에 영향을 줄 수 있기 때문에 미리 전송한다는 의미이다.
요청 헤더에 다음 값이 포함
- origin: 어디서 요청을 했는지 서버에 알려주는 주소
- access-control-request-method: 실제 요청이 보낼 http 메서드
- access-control-request-headers: 실제 요청에 포함된 header
응답 헤더에는 다음 값이 포함
- access-control-allow-origin: 서버가 허용하는 출처
- access-control-allow-methods: 서버가 허용하는 http 메서드 리스트
- access-control-allow-headers: 서버가 허용하는 header 리스트
- access-control-max-age: 프리 플라이트 요청의 응답을 캐시에 저장하는 시간
3. 신용 요청(Credentialed Request)
- 쿠키, 인증 헤더, TLS 클라이언트 인증서 등의 신용정보와 함께 요청
- CORS 정책은 기본적으로 다른 출처 요청에 인증정보 포함을 허용하지 않는다.
- 요청에 인증을 포함하는 플래그가 있거나 access-control-allow-credentials가 true로 설정한다면 요청할 수 있다.
- 서버 응답에 access-control-allow-crendentials 가 true가 아니거나 access-control-allow-origin 헤더에 있는 값이 허용된 출처가 아니라면 아래와 같이 오류가 발생
해결방법
서버에서 직접 제어하기
- 서버에서 Access-Control-Allow-Origin 헤더에 클라이언트 출처를 허용
- Open API를 사용할 때 처럼 서버를 직접 제어할 수 없는 경우에는 사용할 수 없다.
프록시 서버 사용
- CORS 정책은 브라우저에서 강제하는 방법이다.
- 서버 간 통신에서는 SOP 정책이 적용되지 않으므로 프록시 서버를 사용하자
- 클라이언트에게 응답을 보낼 때 Access-Control-Allow-Origin의 출처로 요청 도메인의 출처를 포함시켜주면 되기 때문에 CORS 문제를 해결할 수 있다.
SOP(Same-Origin Policy)
웹 생태계에서 다른 출처로의 리소스 요청을 제한하는 정책 중 하나로, 같은 출처의 리소스만 공유할 수 있도록 제한하는 정책
정리
- 웹브라우저에서 외부 도메인 서버와 통신하기 위한 방식을 표준화한 HTTP 헤더 기반 메커니즘
- 서버 쪽에서 클라이언트를 대상으로 리소스 허용 여부를 결정하는 방법
- 같은 origin에서 ajax를 시도 시 CORS 문제가 발생하지 않는다.
- 클라이언트는 서버가 어떤 origin 요청을 허용하는지는 알 수 없다
- CORS를 해결하려면 두 가지 방법이 있다.
- 서버에서 직접 제어 가능한 경우 Access-Control-Allow-Origin 헤더에 클라이언트 출처를 허용
- 서버에서 직접 제어가 불가능한 경우 프록시 서버를 사용
참고 글
https://velog.io/@kansun12/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-CORS