Rootable의 개발일기
CORS(Cross-Origin Resource Sharing) Policy 본문
JSON 통신을 하는 프로젝트를 진행하면 다음과 같은 에러를 만날 수 있다.
그래서 해당 글에서는 CORS 정책과 관련된 내용을 정리해 보려고 한다.
📌 CORS란?
다른 출처 간의 자원을 공유하는 정책
🔍 출처(Origin)
우리가 어떤 사이트에 접근할 때 작성하는 URL은 아래와 같이 구성되어 있다.
여기서 Protocol, Host, Port를 합친 URL을 출처(Origin)이라고 한다.
📌 웹 보안 정책
웹은 보안을 위해 콘텐츠 보안, 연결 보안, 데이터 보안, 정보 유출, 무결성, 클릭재킹 보호, 사용자 정보 보안 등의 주제로 나눠 각 주제에 대한 보안 솔루션을 갖고 있다. 이 중에서 무결성을 위해 출처에 대한 정책을 갖고 있는데 이것에 대해 이야기하려고 한다.
🔍 Same Origin Policy(SOP, 동일 출처 정책)
A 라는 출처에서 로드한 문서나 script가 B라는 출처의 리소스와 상호 작용할 수 있는 방식을 제한하는 중요한 보안 메커니즘을 말한다.
즉, 동일 출처 서버에 있는 리소스는 자유롭게 가져올 수 있지만, 다른 출처 서버에 있는 리소스는 상호작용이 불가능하다는 말이다.
이 정책을 따르지 않는다는 것은 출처가 다른 외부의 요청을 받아들이는 것이므로 보안상 매우 취약한 상태라고 할 수 있다. 가령, CSRF(Cross-Site Request Forgery) 나 XSS(Cross-Site Scripting)와 같은 공격의 전제 조건은 외부의 요청을 받아들이는 것에서 시작한다.
✔ SOP 정책을 따르는 리소스
XMLHttpRequest
Fetch API 스크립트
외부로부터 ajax 요청
🚖 출처 비교와 차단은 브라우저가 수행
== 서버 간 통신은 SOP로부터 자유롭다.
== Proxy 서버를 통해 우회하는 방법도 있다.
🔍 Cross-Origin Resource Sharing Policy (CORS, 교차 출처 리소스 공유)
최근에는 다른 출처에 있는 리소스를 가져와서 사용하는 일이 매우 흔하므로 SOP의 예외 조항인 CORS 정책을 두게 되었다.
✔ CORS 정책을 따르는 리소스
<img>, <video>, <audio>, <embed>, <object>
<link> 태그로 다른 도메인의 CSS 가져오기
<script> 태그로 다른 도메인의 JS 가져오기 (특정 API는 차단될 수 있음)
<iframe>으로 삽입되는 모든 것
📌 CORS 작동 방식
🔍 예비 요청 (Preflight Request)
브라우저는 서버와 잘 통신되는지 확인하기 위해 본 요청에 앞서 예비 요청을 보낸다. 이것은 본 요청을 보내기 전에 브라우저 스스로 안전한 요청인지 미리 확인하는 절차이다.
이처럼 브라우저가 예비 요청을 보내는 것을 Preflight라고 부르며, 해당 요청은 OPTIONS라는 HTTP 메서드를 사용한다.
요청 필드 의미
<Browser>
Origin: 자신의 출처
Access-Control-Request-Methods: 실제 요청에 사용할 메서드
Access-Control-Request-Headers: 실제 요청에 사용할 헤더들
<Server>
Access-Control-Allow-Origin: 허용되는 Origin 목록
Access-Control-Allow-Methods: 허용되는 메서드 목록
Access-Control-Allow-Headers: 허용되는 헤더들의 목록
Access-Control-Max-Age: 해당 예비 요청이 브라우저에 캐시 될 수 있는 시간(초 단위)
👉 에러의 원인
서버에서 허용하는 Origin 목록에 해당 브라우저의 Origin이 없었기 때문
✔ Access-Control-Max-Age 설정을 하는 이유
보안 강화 목적으로 예비 요청을 사용하는 것은 바람직하지만 이로 인해 요청 횟수가 늘어나고 응답 속도가 느려져 성능 측면에선 불리한 요소가 된다.
그래서 Access-Control-Max-Age 헤더를 사용하여 캐시 될 시간을 명시하면 해당 예비 요청을 캐싱하여 최적화시킬 수 있다.
설정 후, 브라우저는 설정된 시간 동안 캐시에 결과를 저장하고, 다음 예비 요청 때 그 응답이 이미 캐시에 들어있다면 요청을 절약하는 방식으로 성능을 최적화하는 것이다.
🔍 단순 요청 (Simple Request)
예비 요청을 생략하고 바로 서버에 본 요청을 보낸 후, 서버가 이에 대한 응답 헤더에 Access-Control-Allow-Origin 헤더를 보내주면 브라우저의 Origin과 비교하여 CORS 위반 여부를 확인하는 방식이다.
단순 요청을 하는 경우는 다음과 같다.
- GET, POST, HEAD 요청
- {Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width} 헤더
- Content-Type 헤더: {application/x-www-form-urlencoded, multipart/form-data, text/plain}
🔍 인증된 요청 (Credentialed Request)
클라이언트에서 서버에게 자격 인증 정보(Credential)를 실어 요청할 때 사용되는 요청이다.
자격 인증 정보: 쿠키, Authorization 헤더에 설정하는 토큰 값 등
📌 해결 방법 (Spring)
🔍 @CrossOrigin (Controller)
가장 간단한 방법으로 @CrossOrigin을 사용하면 CORS 정책을 설정할 수 있다. originPatterns로 설정한 URL은 Access-Control-Allow-Origin에 설정된다.
🔍 Spring 설정 파일에 설정 추가
@WebMvcConfigurer를 implements 했고, @Configuration이 달린 파일에서 서버의 헤더 필드를 설정하여 CORS 정책을 만족하도록 하는 방법이다.
🔍 Filter 에서 CORS 설정
References:
https://velog.io/@wogkr1383/SOP%EC%99%80-CORS
SOP와 CORS
📌 SOP와 CORS에 대해서 설명해주세요
velog.io
🌐 악명 높은 CORS 개념 & 해결법 - 정리 끝판왕 👏
악명 높은 CORS 에러 메세지 웹 개발을 하다보면 반드시 마주치는 멍멍 같은 에러가 바로 CORS 이다. 웹 개발의 신입 신고식이라고 할 정도로, CORS는 누구나 한 번 정도는 겪게 된다고 해도 과언이
inpa.tistory.com
https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
Same-origin policy - Security on the web | MDN
The same-origin policy is a critical security mechanism that restricts how a document or script loaded by one origin can interact with a resource from another origin.
developer.mozilla.org
https://steady-coding.tistory.com/616
[Spring] Spring에서 CORS 이슈를 해결하는 방법
spring-study에서 스터디를 진행하고 있습니다. CORS(Cross-Origin Resource Sharing) CORS는 Cross-Origin Resource Sharing 의 줄임말로, 교차 출처 리소스 공유를 의미하며, 교차 출차는 ‘다른 출처’라고 생각하면
steady-coding.tistory.com
'Network' 카테고리의 다른 글
JWT vs Session (0) | 2024.01.26 |
---|---|
JWT (JSON Web Token) (4) | 2024.01.25 |
HTTP 응답/상태 코드 (0) | 2023.07.11 |
API vs HTTP API vs REST API (0) | 2023.07.10 |
HTTP 메서드 (0) | 2023.07.10 |