일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- 힙
- CORS
- 우선순위 큐
- OSI 7 layer
- 내부망
- 좌표 압축
- 파이썬
- 이분 탐색
- heap
- 명령어
- 18870
- cron expression
- cron표현식
- 백준
- Docker Compose
- datastructure
- python
- queue
- powershell
- network
- 자료구조
- docker
- priority queue
- cron
- array
- 스케쥴링
- 개념 정리
- CentOS
- Cross-origin Resource Sharing
- 시험준비
- Today
- Total
고양이와 코딩하기
(CORS) Cross-Origin Resource Sharing 본문
프론트엔드 개발 당시 개발자 도구 콘솔창으로 CORS관련 빨간 메시지가 뜬 적이 정말 많았다.
당시에는 그때그때 마다 구글링을 통해 주먹구구식으로 해결했었고, 그런 과정이 반복되면서 자연스럽게 CORS가 무엇인지 어렴풋이 알게되었다.
요즘 시큐리티 공부 관련으로 CORS를 다시 보게되면서 이번 기회에 자세히 정리해보려고 한다.
목차
1. CORS란?
브라우저는 보안상 기본적으로 SOP(Same Origin Policy, 동일 출처 정책)가 적용된다. 즉, 브라우저에서 A라는 사이트를 통해 B 서버에 요청을 보내면 기본적으로 막힌다는 것이다.
하지만, 웹개발 기술 및 방법론이 발달함에 따라 프론트엔드와 백엔드를 분리하는 경우가 많아졌고, 이뿐만 아니라 Open API 등 다른 여러 사이트에서 유용하게 이용할 수 있는 API 서비스들이 많이 생겨나면서, 사실상 SOP를 지키기 어려운 상황이 많이 발생했다.
CORS란 브라우저가 자신의 Origin(웹페이지의 출처, ex> domain or ip:port)이 아닌 다른 어떤 Origin으로 부터 자원을 로딩하는 것을 허용하도록 서버가 허가해주는 HTTP Header 기반 매커니즘이다.
따라서 cors는 실제 요청을 허가할 것인지 확인하기 위해서 브라우저가 보내는 Preflight Request(사전 요청) 메커니즘에 의존한다.
CORS 표준은 서버가 HTTP Response header에 웹 브라우저가 해당 정보를 읽는 것이 허용될 수 있는 조건(Access-Control-Allow-Origin 등)을 서술함으로써 동작한다. 또한 서버 데이터에 영향을 줄 수 있는 요청의 경우(GET이외의 요청), CORS 명세는 브라우저가 HTTP OPTIONS 메서드로 해당 request url에 대해 서버에서 지원하는 메서드들을 요구하는 “Preflight Request”를 보내고, 서버로부터 승인 받으면 실제 요청을 보낸다.
CORS 실패는 오류를 발생시키지만, 보안상의 이유로 오류에 대한 세부 사항은 JavaScript에 제공되지 않는다. 구체적으로 무엇이 잘못되었는 지를 확인하려면 브라우저의 콘솔에서 세부사항을 살펴볼 수 있다.
2. CORS 접근 제어 시나리오
2.1 Simple Request
- 앞서 말한 preflight request를 유발하지 않는 단순한 요청을 말한다. 서버에 바로 실제 요청을 보내고 서버는 CORS 허용 조건(Access-Control-Allow-Origin 등)을 헤더에 붙혀서 응답을 보내주면 브라우저가 정책 위반 여부를 검사한다.
* 아래 예시는 RHEL8 기준
*단순 요청을 충족하는 조건
- HTTP Method: GET, HEAD, POST
*HEAD: Response header만 요청하는 메소드 - User Agent가 자동으로 설정한 헤더 외에, 수동으로 설정할 수 있는 헤더 제한(Fetch 명세에서 "CORS-safelisted request-header"로 정의한 헤더 참고): Accept, Accept-Language, Content-Language, Content-Type, Range
- Content-Type 제한
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
Rest API에서 파일 업로드(multipart/form-data)외에는 보통 application/json을 사용하기 때문에 거의 대부분은 Preflight Request를 보낸다.
2.2 Preflight Request + Requests with credentials
- Preflight Request: 서버 데이터의 수정을 방지하기 위해 실제 요청이 안전한지 판단하기 위해 OPTIONS 메서드로 사전 요청을 보내는 것을 의미한다.
- Requests with credentials: HTTP 쿠키와 HTTP 인증정보를 이용한 “자격증명이 포함된” 요청을 하는 것을 의미한다.
CORS 사전 요청에는 자격 증명이 절대로 포함되지 않아야 한다. 사전 요청에 대한 응답은 실제 요청이 자격 증명과 함께 수행될 수 있음을 나타내기 위해 Access-Control-Allow-Credentials: true 를 명시해야 한다.
통상적인 로그인을 위한 POST 요청이며 403 에러로 실패한 예제(패스워드 잊어버림..)이다.
보면 login이라는 요청에 실제로 2번 요청이 보내진 것을 볼 수 있고, 첫 요청은 preflight 타입이라고 되어있다.
Preflight 요청을 자세히 살펴보자, Request Method에 OPTIONS로 되어 있고, Status Code가 200인 것으로 보아 CORS 허용 조건에 맞아 서버가 요청을 수락한 것을 알 수 있다.
다음으로 Request Headers를 보면 Access-Control-**로 되어 있는 2가지 속성이 있다.
Access-Control-Request-Method 헤더는 Preflight 요청의 일부로써 서버에게 실제 요청이 전송될 때 POST 요청 메서드를 사용할 것임을 알려준다.
Access-Control-Request-Headers 헤더는 실제 요청이 전송될 때 Content-Type 를 사용할 것임을 서버에게 알려준다. 서버는 이러한 조건 하에서 요청을 수락할 수 있는지 여부를 결정한다.
마지막으로 Response Headers를 보면 Access-Control-**로 되어 있는 6가지 속성이 있다.
Access-Control-Allow-Credentials은 브라우저에서 프론트엔드 자바스크립트가 자격증명(쿠키, authorization 헤더들 또는 TLS 클라이언트 인증서)에 대해 접근 가능하도록 허용여부를 설정하는 옵션이다. cross origin 요청을 위해서는 API 서버에서 Access-Control-Allow-Credentials를 true로 설정해주어야할 뿐만 아니라, 요청하는 클라이언트의 프론트엔드 측에서도 Request.credentials을 “include”로 설정해주어야한다.
*Request.credentials: Fetch API의 Request 인터페이스의 credentials은 user agent가 다른 도메인으로 cookie들을 전송할지 여부에 대한 설정이다.
- omit: 절대로 cookie 들을 전송하거나 받지 않는다.
- same-origin: 요청 URL이 호출 script 와 동일 출처(same origin)에 있다면, user credentials을 전송한다. 이것은 default 값이다.
- include: cross-origin 호출이라 할지라도 언제나 user credentials을 전송한다.
Access-Control-Allow-Origin은 서버에서 CORS를 허용하는 Origin에 대한 설명이고,
Access-Control-Allow-Methods는 해당 요청 경로(여기에서는 “/user/login”)에 대해 유효한 HTTP Method 종류이다.
Access-Control-Allow-Headers는 실제 요청에 사용할 수 있는 허용된 헤더임을 확인해준다.
Access-Control-Expose-Headers 헤더를 통해 서버는 cross-origin 요청에 대한 응답으로 브라우저에서 실행 중인 스크립트가 사용할 수 있는 응답 헤더를 지정할 수 있다. 기본적으로는 Fetch 명세에서 "CORS-safelisted request-header"로 정의한 헤더들만 노출된다.
Access-Control-Max-Age 는 또 다른 사전 요청을 보내지 않도록 사전 요청에 대한 응답을 얼마나 오래동안 캐시할 수 있는지 서버에서 설정한 초 단위 시간 값이다. 최대 캐시시간은 86400초(=24시간)이다.
3. 주의사항
3.1 자격증명이 포함된 요청에서의 와일드카드 제한
- 서버는 Access-Control-Allow-Origin 응답 헤더 값으로 "*" 와일드카드를 지정해서는 안 되며, 대신 명시적인 출처를 지정해야 한다. 예> Access-Control-Allow-Origin: https://example.com.
- 서버는 Access-Control-Allow-Headers 응답 헤더 값으로 "*" 와일드카드를 지정해서는 안 되며, 대신 명시적인 헤더 이름 목록을 지정해야 한다. 예> Access-Control-Allow-Headers: X-PINGOTHER, Content-Type.
- 서버는 Access-Control-Allow-Methods 응답 헤더 값으로 "*" 와일드카드를 지정해서는 안 되며, 대신 명시적인 메서드 이름 목록을 지정해야 한다. 예> Access-Control-Allow-Methods: POST, GET.
- 서버는 Access-Control-Expose-Headers 응답 헤더 값으로 "*" 와일드카드를 지정해서는 안 되며, 대신 명시적인 헤더 이름 목록을 지정해야 한다. 예> Access-Control-Expose-Headers: Content-Encoding, Kuma-Revision.
요청에 자격 증명(가장 일반적으로는 Cookie 헤더)이 포함되고 응답에 Access-Control-Allow-Origin: * 헤더(즉, 와일드카드)가 포함되어 있으면, 브라우저는 응답에 대한 접근을 차단하고 개발자 도구 콘솔에 CORS 오류를 보고한다. 응답의 Access-Control-Allow-Origin 헤더 값에 실제 출처가 아닌 "*" 와일드카드인 경우 응답의 Set-Cookie 헤더는 쿠키를 설정하지 않는다.
3.2 서드 파티 쿠키
CORS 응답에 설정된 쿠키는 일반적인 서드 파티(third-party) 쿠키 정책의 적용을 받는다. 위의 예에서, 페이지는 foo.example 에서 로드되지만, 응답의 Cookie 헤더는 bar.other 에서 전송되므로 사용자의 브라우저가 모든 서드-파티 쿠키를 거부하도록 설정된 경우 해당 쿠키는 저장되지 않는다.
요청의 쿠키도 일반적인 서드-파티 쿠키 정책에 따라 억제될 수 있다. 따라서 강제된 쿠키 정책은 이 장에서 설명된 기능을 무효화 할 수 있으며, 자격 증명이 포함된 요청을 전혀 수행할 수 없게 만들 수 있다.
참고자료
Cross-Origin Resource Sharing (CORS) - HTTP | MDN
Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources. CORS also relies on a mechanism by which
developer.mozilla.org
'D E V E L O P E R 💻 > Today I Learned' 카테고리의 다른 글
[정보처리기사] 실기 준비 오답노트 (1) (0) | 2025.03.06 |
---|---|
알고리즘 - 우선순위 큐, 힙 (0) | 2023.01.26 |
자료구조 - Stack 알아보기 (0) | 2021.11.20 |
자료구조 - Queue 알아보기 (0) | 2021.11.03 |
자료구조 - Array 알아보기 (0) | 2021.11.03 |