CORS란?
Cross-Origin Resource Sharing.
영어를 직역하자면, 출처가 다른 리소스를 공유하는 정책.
웹 브라우저에서 Cross-Origin(다른 출처) 요청을 허용하도록 서버 응답 방식을 설정하는 메커니즘. 한 출처(Origin)에서 로드된 리소스(데이터)가 다른 출처의 리소스(데이터)에 접근할 수 있도록 허용하는 보안 기능. 이를 통해 브라우저는 보안적으로 안전하게 외부 API나 리소스를 호출할 수 있다.
기본적으로, 브라우저는 '동일 출처 정책'을 따르기 때문에, 다른 출처의 리소스에 대한 요청을 차단하여 보안을 강화한다. 다른 출처의 리소스에 접근하려면 CORS 설정으로 안전하게 허용해야 한다.
동일 출처 정책(Same-Origin Policy)
웹 브라우저에서 보안을 강화하기 위해, 한 출처에서 로드된 문서나 스크립트가 다른 출처의 리소스에 접근하지 못하도록 제한하는 보안 정책. 만약에 '동일 출처 정책'이 없으면 아래와 같은 보안 문제가 발생할 수 있다.
- 크로스 사이트 스크립팅(XSS, Cross-Site Scripting):
공격자가 웹 페이지에 악성 스크립트를 삽입하여, 사용자의 브라우저에서 악의적인 사이트가 실행되도록 만드는 공격 기법. 이를 통해 사용자의 세션 쿠키나 개인 정보를 훔칠 수 있다. - 크로스 사이트 요청 위조(CSRF, Cross-Site Request Forgery):
사용자가 인증된 세션을 가지고 있는 상태에서, 공격자가 사용자의 인증 정보를 사용하여, 악의적인 사이트가 사용자 몰래 요청을 보내도록 만드는 공격 기법. 이를 통해 사용자의 계정에서 원치 않는 작업이 수행될 수 있다. - 개인정보 노출: 다른 출처의 악성 사이트에 접속했을 때, 해당 사이트가 사용자 정보를 무단으로 접근하고 사용할 수 있다.
웹 페이지는 보안에 취약하다. 개발자도구 열면 코드를 볼 수 있으니까, 만약에 브라우저에 이런 보안 정책이 없다면 우리의 개인정보가 아주 손쉽게 남에게 노출/탈취될 수 있다. 그래서 브라우저는 기본적으로 '동일 출처 정책'을 따르면서, 별도의 CORS 설정을 통해 다른 출처의 리소스도 공유할 수 있도록 허락하는 것이다.
그렇다면 출처가 다르다는 것은 어떻게 알 수 있을까?🤔
URL의 구조
JS에서 쿼리스트링을 공부하면서 사용했던 사진을 다시 가져왔다.
URL은 웹 자원을 식별하고 위치를 지정하는 문자열로, 다양한 구성 요소로 이루어져 있다.
- 프로토콜 Protocol : 어떤 방식으로 서버와 통신하고 데이터를 전송할 것인가를 나타낸다. scheme라고도 한다.
https는 http에 'secure'를 붙인 것으로 보안이 더 강화된 http 프로토콜이다. - 호스트 Host : 도메인+포트번호. 도메인은 Subdomain, Secondary Domain, Top-Level Domain으로 나눌 수 있다.
- Subdomain : 호스트 주소 맨 앞의 www나 blog, news, weather 등
- Secondary Domain : 구글이나 네이버 등 주소의 메인 이름 부분
- Top-Level Domain : 주소 끝의 com, net, kr 등. 해당 주소를 운영하는 기관이나 국가를 나타낸다.
- 포트번호 : 특정 서버의 리소스에 접근하기 위한 포트. React 프로젝트에서 localhost:3000의 3000이 포트번호이다. 배포된 사이트의 경우에는 생략되기도 한다.
- 경로 : 서버 내에서 리소스의 위치. (현재 열려있는 페이지의 위치)
- 쿼리스트링 : 물음표부터 그 뒤의 부분으로, 추가적인 데이터 전달을 위한 파라미터이다. "parameter=value"의 형식으로 key와 value를 적고, 파라미터가 여러 개일 경우 &(connector)로 연결해서 작성한다.
여기에서 '오리진'에 해당하는 → 프로토콜, 도메인, 포트번호가 다른 경우에는 CORS 에러가 생기게 된다.
지금 CORS를 공부하면서, 5개월 전 팀플에서 나를 힘들게 했던 문제가 클라이언트와 서버의 프로토콜이 서로 달라서 생겼던 CORS 에러인걸 깨달았다.😂
(말이 나왔으니 슬쩍 가져와보는 팀플 당시의 기록😝 - https://hjinn0813.tistory.com/62)
[코딩온] 프론트엔드 입문 Day 54~55 (3차 프로젝트 7, 발표)
3차 프로젝트와 관련한 마지막 주간기록.✍이번주에는 작업을 마무리하고, vercel로 배포하고 오류를 수정하고, 최종 발표와 시상까지 있었다.13일 월요일 - Day 54새벽부터 컨디션이 너무 안 좋아
hjinn0813.tistory.com
그렇다면 CORS 정책은 누가, 언제 검사하는걸까?🤔
CORS의 작동원리
CORS 정책은 클라이언트(브라우저)에서 검사한다.
서버에 요청을 보낼 때, 브라우저가 출처를 비교하고 CORS 헤더를 확인하는 방식으로 작동한다.
구체적인 작동원리는 아래와 같다.
- HTTP 요청 전송: 클라이언트(브라우저)가 서버에 API 요청을 보낼 때, 요청이 '동일 출처 정책'에 해당하는지 오리진(프로토콜, 도메인, 포트번호)를 기반으로 출처를 비교한다.
- 요청 방식 확인: 클라이언트는 페이지 로드나 데이터 통신 같은 요청을 보낼 때, 사용하는 메서드(GET, POST 등)와 헤더에 따라 '프리플라이트 요청'을 할지, '심플 리퀘스트'로 바로 진행할지 결정한다.
- 프리플라이트 요청(Preflight Request): 사전 검증 방식. GET, POST 외의 요청을 보낼 때나 특별한 정보를 담고 있는 커스텀 헤더가 요청에 들어있는 경우에, 브라우저는 먼저 OPTIONS 메서드를 사용하여 서버가 이런 요청을 받아줄 수 있는지 확인한다.
- 심플 리퀘스트(Simple Request): 사후 검증 방식. GET, POST 메소드를 사용했거나 일반적인 헤더만 사용한 경우에, 브라우저는 요청을 바로 서버로 보낸다. - 서버 응답: 서버는 '프리플라이트'와 '심플 리퀘스트' 등 클라이언트가 확인한 요청 방식에 대해서 허용하는 메서드, 헤더, 오리진이 뭔지 알려준다. CORS 관련 헤더에 Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers 등을 포함하여 어떤 출처의 요청을 허용할 것인지를 명시해서 보내주는 것이다.
- CORS 헤더 확인: 클라이언트는 서버의 응답에서 CORS 헤더를 확인한다.
서버에서 요청을 허용했다면 브라우저는 실제 요청을 진행하고, 그렇지 않으면 CORS 에러를 발생시켜 요청을 차단한다.
💡 심플 리퀘스트(Simple Request)의 검증방식
1. 브라우저가 서버로 실제 요청을 보낸다.
2. 서버는 응답 헤더에 Access-Control-Allow-Origin을 넣어 보낸다.
3. 브라우저는 요청의 Origin과 서버에서 받은 Access-Control-Allow-Origin이 일치하는지 확인한다.
4. 일치하지 않으면 CORS 에러를 띄우고 서버에서 받은 응답을 사용할 수 없게 한다. 응답을 받은 후에 에러가 뜨기 때문에, 서버에서는 이미 관련 로직이 수행되어 DB나 리소스가 변경되었을 수 있다.
💡 프리플라이트 요청(Preflight Request)의 검증방식
1. 브라우저가 실제 요청에 사용할 메소드와 헤더를 Access-Control-Request-* 헤더에 담아 OPTIONS 요청을 보낸다.
2. 서버는 허용되는 메소드와 헤더 목록을 Access-Control-Allow-* 헤더로 보낸다.
3. 브라우저는 자신이 보낸 Access-Control-Request-* 헤더와 서버에서 받은 Access-Control-Allow-* 헤더를 비교하여 CORS 정책에 맞는지 확인한다.
4. 검증을 통과하면 브라우저의 원래 요청을 서버로 보낸다. 통과하지 못하면 CORS 에러를 띄우고, 실제 요청을 보내지 않는다.
💡 프리플라이트 요청(Preflight Request)을 통과하지 못하는 경우
1. 프리플라이트 응답 헤더에 Access-Control-Allow-* 헤더가 없을 때: 서버가 CORS 요청을 허용하는지에 대한 정보를 제공하지 않으면 요청이 통과되지 않음.
2. Access-Control-Allow-Headers에 Access-Control-Request-Headers가 하나도 포함되지 않을 때: 요청에서 사용된 커스텀 헤더가 서버에서 허용되지 않으면 요청이 통과되지 않음.
3. Access-Control-Allow-Method와 Access-Control-Request-Method가 일치하지 않을 때: 요청에 사용된 HTTP 메서드가 서버에서 허용하는 메서드 목록에 없으면 요청이 통과되지 않음.
4. 현재 사이트가 Access-Control-Allow-Origin에 없는 주소일 때: 요청의 출처(Origin)가 서버에서 허용하는 출처 목록에 포함되지 않으면 요청이 통과되지 않음.
이렇게 하여 CORS의 개념과 작동원리에 대해 알게 되었다!👏
지난 여름 면접을 보러 다닐 때, 포트폴리오에서 팀플 부분 트러블슈팅을 설명하면서 그게 어떤 문제이고 왜 발생했는지는 알았지만 정확한 이름은 몰랐는데, 이번에 알게 되어서 뿌듯하달까..🤭
앞으로도 착실하게 꾸준히 성장해보자! 🌱

참고 글
'📚 자료실' 카테고리의 다른 글
SFTP, FTP, SSH 기본 개념 (0) | 2024.10.15 |
---|---|
프로토콜의 개념과 종류, OSI 7계층, TCP/IP 4계층 (0) | 2024.10.15 |
세션, 토큰, 캐시, 쿠키, 로컬 스토리지, 세션 스토리지 (0) | 2024.09.04 |
프록시 서버(Proxy Server)의 정의와 사용 이유 (0) | 2024.08.14 |
CRP 프로세스/ SPA, MPA/ 렌더링(CSR, SSR, SSG)/ SEO (0) | 2024.08.05 |