참고: https://developer.mozilla.org/ko/docs/Web/HTTP/Access_control_CORS
참고2: https://www.popit.kr/cors-preflight-인증-처리-관련-삽질/
처음 전송되는 리소스의 도메인과 다른 도메인으로부터 리소스가 요청되는 경우 해당 리소스는 cross-origin HTTP 요청으로 요청을 보낸다. css, image, script 리소스들은 각각의 출처로 부터 읽어온다.
단, 보안상의 이유로 XMLHttpRequest
는 Same-origin Policy
를 따른다. 따라서, 같은 도메인이 아닌 도메인으로 HTTP 요청을 보내기 위해서는 CORS 메커니즘을 이용해야한다.
Same-origin Policy
참고: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
Same-origin Policy란 다른 Origin과 리소스를 주고 받을 때 문서나 스크립트를 제한하는 보안 메커니즘이다. 이는 악의적인 문서나 스크립트로부터 리소스를 보호하기 위한 방안이다.
Cross-origin Network access
Cross-origin 통신의 유형에는 다음 3가지가 있다.
- Cross-origin writes
links, redirects, form 제출 등이 이 유형에 해당한다.
- Cross-origin embedding
<script src="..."></script>
형태의 javascript<link rel="stylesheet" href="..." />
형태의 CSS. cross-origin CSS의 경우는 올바른Content-Type
헤더가 필요하다.<img>
태그로 보여지는 이미지<video>
와<audio>
<object>
,<embed>
,<applet>
@font-face
적용되는 font.<frame>
이나<iframe>
. 사이트에서는 cross-origin frame을 피하기 위해X-Frame-Options
헤더를 사용할 수 있다.
- Cross-origin read
read는 일반적으로 허용되지 않는다. 여기서 read는 다른 도메인의 리소스를 실행한다는 것을 의미한다. (리소스를 읽어들이는 것)
CORS 요청
간단한 요청
CORS 요청은 사용자 데이터 상에서 부수 효과를 일으킬 수 있는 HTTP 요청 메서드나 특정 MIME 타입에 대해 사전 요청을 강제한다. 단, 사전 요청을 보내지 않는 경우도 있는데 다음 조건을 모두 만족해야만 사전 요청을 보내지 않는다.
- GET, HEAD, POST 요청
- 사용자 에이전트가 자동으로 설정하는 헤더인
Connection
,User-Agent
와 Fetch spec에서 금지된 헤더를 제외하고 수동 설정이 허용된 헤더만을 가지는 경우- 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
- 어떠한 이벤트 리스너도 요청에 사용된 XMLHttpRequestUpload 오브젝트에 등록되지 않는 경우
- ReadableStream이 요청에서 사용되지 않은 경우
사전 요청
위 간단한 요청의 조건에 하나라도 위반하는 경우 사전요청을 보낸다. 사전요청은 실제 요청이 전송하기 전에 안전한지 아닌지를 판단하기 위해 접근하려는 리소스에 OPTIONS
요청을 보내는 것이다.
OPTIONS와 HEAD 메서드 참고: https://stackoverflow.com/questions/6660019/restful-api-methods-head-options
사전 요청으로 보통 Access-Control-Request-Method
와 Access-Control-Request-Headers
를 보내는데 서버에 Access-Control-Request-Method
로 실제 요청이 위 메서드로 전달됨을 알려주고 Access-Control-Request-Headers
로 실제 요청을 보낼 때 사용될 헤더들을 알려주는 역할을 한다.
이후 서버는 Access-Control 헤더를 사용하여 관련 응답을 해준다.
CORS 관련 HTTP 요청 헤더
XMLHttpRequest 기능을 사용하는 경우 프로그램 상으로 cross-origin 관련 요청 헤더를 설정해서는 안된다.
- Origin
cross-site 접근 요청 또는 사전 요청의 출처를 알려준다.Origin: <origin>
과 같이 설정되며 값으로 들어가는 origin은 서버를 가리키는 URI이다. 어떠한 경로 정보도 포함하지 않으며 서버 이름만을 포함한다.
어떤 접근 제어 요청에서든 Origin 헤더는 항상 전송된다.
- Access-Control-Request-Method
실제 요청이 일어나는 경우 어떤 HTTP 메서드가 사용될 것인지 서버에 알리는 용도로 사용. 사전 요청을 보낼 때 사용한다. (실제 요청시에는 위 헤더는 포함하지 않음)
Access-Control-Request-Method: <method>
와 같이 설정할 수 있다.
- Access-Control-Request-Headers
실제 요청이 일어나는 경우 어떤 요청 헤더가 사용될 것인지 서버에 알리는 용도로 사용. 사전 요청을 보낼 때 사용한다. (실제 요청시에는 위 헤더는 포함하지 않음)
Access-Control-Request-Headers: <header-name>[, <header-name>]...
와 같이 설정할 수 있다.
CORS 관련 HTTP 응답 헤더
CORS 접근 제어를 위해 서버가 응답하는 HTTP 응답헤더.
- Access-Control-Allow-Origin
사전 요청시 반환된 리소스는 반드시 위 헤더를 가지고 있어야한다.Access-Control-Allow-Origin: <origin> | *
과 같은 형식이며, origin은 URI를 특정한다.
와일드카드*
를 사용하면 어떤 출처든 허용함을 의미한다.
만약, 서버가 단일 출처를 지정하는 경우, 클라이언트에게 서버 응답이 Origin 요청 헤더의 값과는 다르다는 것을 알려주기 위한 Vary
헤더가 필요하다. Vary
에는 Origin을 포함해야한다.
- Access-Control-Expose-Headers
브라우저가 접근할 수 있도록 해주는 서버 화이트리스트 헤더를 허용하는 헤더.
- Access-Control-Max-Age
사전 요청의 결과가 얼마나 오랫동안 캐시될 수 있는지 알려주는 헤더.Access-Control-Max-Age: <seconds>
와 같은 형식으로 사용한다. 단위는 초 단위이다.
- Access-Control-Allow-Credentials
Credientials
헤더가 true인 경우 요청을 처리할 수 있는지 없는지를 알려주는 헤더이다.Access-Control-Allow-Credentials: true | false
형식을 가지며 true인 경우만 요청을 처리할 수 있다.
- Access-Control-Allow-Methods
리소스에 접근하는 경우 허용된 메서드들을 지정하는 헤더.Access-Control-Allow-Methods: <method>[, <method>]...
와 같은 형식을 사용한다.
- Access-Control-Allow-Headers
실제 요청이 이뤄지는 경우 어떤 HTTP 헤더가 사용될 수 있는지 알려주는 헤더.Access-Control-Allow-Headers: <header-name>[, <header-name>]...
과 같이 사용.
인증을 활용한 요청
Credentials
헤더를 활용하여 특정 리소스의 보안을 강화하는 방법. 사전 요청이나 간단한 요청시 응답으로 Access-Control-Allow-Credentials
헤더가 true로 설정되지 않다면 리소스에 접근할 수 없다. 또한, 서버는 특정 도메인을 반드시 명시해야한다. 즉, 와일드카드 *
로 Access-Control-Allow-Origin
을 응답하는 경우도 요청을 처리할 수 없다.
'Web Basic > HTTP' 카테고리의 다른 글
HTTP Redirect (0) | 2019.10.13 |
---|---|
컨텐츠 협상 (Content Negotiation) (0) | 2019.10.13 |
HTTP 압축 (Compression) (1) | 2019.10.13 |
HTTP 캐싱 (0) | 2019.10.06 |
HTTP 세션 (0) | 2019.10.06 |