웹 보안에는 동일 출처 정책이 존재합니다.
동일 출처 정책에서는 어떤 출처에서 불러온 문서나 스크립트의 출처 경로가 같아야 합니다.
이때 경로의 같음은 프로토콜/호스트/포트 등을 비교합니다.
이 경로가 모두 같아야 같은 출처라고 인식하여 문제가 발생하지 않습니다.
SOP(Same-Origin Policy) 원칙하에 다른 출처의 리소스를 가져올때 필요한 체제가 CORS(Cross Origin Resource Sharing) 입니다.
cors는 브라우저에서 비교하고 판단합니다.
출처가 다른 요청이여도 서버에서는 요청을 받고 정상적인 응답을 보내줍니다.
하지만 브라우저에서 다른 출처에서온 경우 해당 응답을 reject 합니다.
cors 체제하에서 요청은 크게 두개의 종류로 나뉘어 집니다.
- 단순 요청
- 사전 요청
- 인증정보를 포함한 요청
단순 요청은 아래의 조건을 모두 만족해야 하는 요청입니다.(and 조건입니다)
- GET, HEAD, POST 중 하나의 요청
- 기본 헤더 외에 Accept, Accept-Language, Content-Language, Content-Type 헤더만 사용 가능
- Content-Type 헤더에는 아래의 값만 사용 가능
- application/x-www-form-urlencoded
- multiplart/form-data
- text/plain
- ReadableStream 객체를 사용하지 않아야 함
- XMLHttpRequestUpload 객체에 이벤트 리스너가 등록되어 있지 않아야 합니다.
하지만 개발을 하다보면 저 조건들을 만족하는 요청을 보내는 경우는 거의 없습니다.
그래서 사전요청이 전달됩니다.
사전에 안전한지 검증을 한 후에 안전한 경우에 원래 요청을 보내게 됩니다.
이걸 preflight 요청이라 합니다.
preflight의 request에서 origin, 요청할 메소드의 종류를 알려줍니다.
그러면 서버에서는 허락된 origin과 허락된 method의 종류를 알려줍니다.
access-control-allow-origin
access-control-allow-methods 의 종류가 일치해야 사전요청은 통과입니다.
이때 access-control-allow-headers, access-control-max-age등 조건을 추가할 수 있습니다.
사전요청이 통과하면 본 요청을 보내게 됩니다!!
인증정보를 포함한 요청
브라우저에서는 쿠키와 인증정보에 민감하여 함부로 설정해주지 않습니다.
따라서 아래의 조건을 만족해야 합니다.
- 서버에서 허용되는 출처에 *(wildcard)를 사용하면 안됩니다.
- Access-Control-Allow-Credentials: true를 허용하는 응답 헤더를 설정하여야 합니다.
- 클라이언트에서 credentials 옵션을 넣어주어야 합니다.
GET /resources/credentialed-content/ 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
Referer: http://foo.example/examples/credential.html
Origin: http://foo.example
Cookie: pageAccess=2
위의 예제는 XMLHttpRequest를 통해 생성된 request 입니다.
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:34:52 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 106
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
[text/plain payload]
위 코드는 서버에서 응답받은 코드 예제 입니다.
set-cookie 헤더가 포함되어 있기 때문에 access-control-allow-origin에 *(와일드카드)로 설정되어 있으면 브라우저에 쿠키는 설정되지 않습니다!
1. 서버에서 보내주는 헤더에 access-control-allow-origin에 프론트 서비스의 url을 추가해주는 것이 해결방법중 하나입니다.
2. webpack의 dev-server에서 proxy 설정을 하여 개발중에 겪는 cors를 임시로 해결할 수도 있습니다.
2022.02.07 - [Frontend/React] - cannot get /path
3. 로컬에서 html 파일내에 type을 module로 설정하고 open 명령어를 통해 여는 경우 cors가 발생합니다.
script의 요청 경로와 html의 현재 경로가 다르기 때문입니다.
이러한 경우 웹서버를 통해 html을 실행하면 cors 문제는 해결될 수 있습니다.
2022.03.21 - [네트워크] - 로컬에서 CORS policy 관련 에러가 발생하는 이유 😃
4. 서버간의 통신은 cors의 제약을 받지 않습니다!!
https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy
'네트워크' 카테고리의 다른 글
html5, 웹 표준 및 웹 접근성 🔥 (0) | 2022.04.13 |
---|---|
쿠키, 세션 🔥 (0) | 2022.04.11 |
OSI 7 layer 🌱 (0) | 2022.04.01 |
로컬에서 CORS policy 관련 에러가 발생하는 이유 😃 (0) | 2022.03.21 |
REST API URI를 설계하는 7가지 규칙 (0) | 2022.02.21 |