CORS
SOP ( SAME ORIGIN POILICY )
동일 출처에 대한 요청에 관해서만 요청을 허락하는 보안 방식
동일 출처란?
프로토콜 / HOST / PORT 가 모두 동일해야 같은 출처로 처리 한다.
Cross Origin
동일 출처가 아니라는 것을 의미한다.
CORS(Cross Origin Resource Sharing)
Cross Origin Resource Sharing
다른 출처에 있는 리소스를 요청를 가능하게 제어하는 방법
단순 요청(Simple requests)
아래의 조건을 모두 만족하면 preflight 요청을 발생시키지 않는다.
Simple requests 용어는 MDN에서 임의로 사용.
다음 중 하나의 메소드
- [GET]
- [HEAD]
- [POST]
헤더
유저 에이전트가 자동으로 설정 한 헤더
- [Connection]
- [User-Agent]
그외 헤더
- [Accept]
- [Accept-Language]
- [Content-Language]
- [Content-Type]
[Content-Type]
헤더는 다음의 값들만 허용됩니다.
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
Simple requests 요청시 Cors 동작 시나리오
https://foo.example
에서 https://bar.other
도메인에 요청시
const xhr = new XMLHttpRequest();
const url = 'https://bar.other/resources/public-data/';
xhr.open('GET', url);
xhr.onreadystatechange = someHandler;
xhr.send();
GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
요청 헤더의 [Origin]
을 보면, https://foo.example
로부터 요청이 왔다는 것을 알 수 있습니다.
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml […XML Data…]
서버는 이에 대한 응답으로 [Access-Control-Allow-Origin]
헤더를 다시 전송
가장 간단한 접근 제어 방법은 [Origin]
헤더와 [Access-Control-Allow-Origin]
을 사용
이 경우 서버는 Access-Control-Allow-Origin: *
, 으로 응답
* 이는 모든 도메인에서 접근할 수 있음을 의미
오직 https://foo.example
의 요청만 리소스에 대한 접근을 허용하려는 경우
Access-Control-Allow-Origin: https://foo.example
으로 응답
Preflight
- OPTIONS 메서드를 통해 미리 요청을 보내 다른 도메인의 리소스에 요청이 가능한 지 확인 작업
- 브라우저 자동 동작
- 요청이 가능하다면 실체 요청을 보냄.
- 불가능 할 경우 403 에러
requests 요청시 Cors 동작 시나리오
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://bar.other/resources/post-here/');
xhr.setRequestHeader('Ping-Other', 'pingpong');
xhr.setRequestHeader('Content-Type', 'application/xml');
xhr.onreadystatechange = handler;
xhr.send('<person><name>Arun</name></person>');
Preflight request
- Origin : 요청 출처
- Access-Control-Request-Method : 실제 요청의 메소드
- Access-Control-Request-Headers : 실제 요청의 추가 헤더
Preflight response
- Access-Control-Allow-Origin : 서버 측 허가 출처
- Access-Control-Allow-Method : 서버 측 허가 메소드
- Access-Control-Allow-Headers : 서버 측 허가 헤더
- Access-Control-Max-Age : Preflight 응답 캐시 기간
Preflight request/response
OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Prefilght request에 실제로 요청할 request 정보를 헤더에 포함해서 전송합니다.
- Access-Control-Request-Method: POST
- Access-Control-Request-Headers: X-PINGOTHER, Content-Type
서버는 사전에 CORS 허용된 옵션을 response 헤더에 포함해서 전송합니다.
- Access-Control-Allow-Origin: http://foo.example
- Access-Control-Allow-Methods: POST, GET, OPTIONS
- Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
- Access-Control-Max-Age: 86400
Real request/response
POST /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: https://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: https://foo.example
Pragma: no-cache
Cache-Control: no-cache
<person><name>Arun</name></person>
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain
서버는 Access-Control-Allow-Methods
로 응답하고 POST
와 GET
이 리소스를 쿼리하는데 유용한 메서드라고 가르쳐줍니다. 이 헤더는 [Allow]
응답 헤더와 유사하지만, 접근 제어 컨텍스트 내에서 엄격하게 사용됩니다.
또한 Access-Control-Allow-Headers 의 값을 "X-PINGOTHER, Content-Type" 으로 전송하여 실제 요청에 헤더를 사용할 수 있음을 확인합니다. Access-Control-Allow-Methods와 마찬가지로 Access-Control-Allow-Headers 는 쉼표로 구분된 허용 가능한 헤더 목록입니다.
마지막으로[Access-Control-Max-Age (en-US)]는 다른 preflight request를 보내지 않고, preflight request에 대한 응답을 캐시할 수 있는 시간(초)을 제공합니다. 위의 코드는 86400 초(24시간) 입니다. 각 브라우저의 최대 캐싱 시간 (en-US)은 Access-Control-Max-Age 가 클수록 우선순위가 높습니다.
'개발관련 > 프론트엔드 지식' 카테고리의 다른 글
OWASP Top 10: 웹 애플리케이션 보안 취약점 (0) | 2023.07.09 |
---|---|
프론트 엔드 면접 관련 공부 (0) | 2023.05.11 |
Next.js 이 4가지는 뭐가 다를까요? 🤔 getInitialProps / getServerSideProps / getStaticPaths / getStaticProps (0) | 2023.04.25 |
SSR vs SSG: Next.js의 렌더링 대결! 어떤 것을 택할까? (0) | 2023.04.21 |
프론트엔드 면접 질문 웹 브라우저 렌더링 원리 feat. ChatGPT (0) | 2023.03.31 |