출처 - https://github.com/jmxx219/CS-Study (opens in a new tab)
SOP, CORS
SOP(Same Origin Policy)
동일 출처 정책
- 동일한 출처의 리소스만 상호작용하는 정책이다.
- 웹 페이지에서 실행되는 스크립트가 다른 도메인의 웹 페이지에 있는 리소스에 접근할 수 없도록 제한하는 정책이다.
- 출처 A(ex:
service.example.com)에서 온 문서가 출처 B(ex:api.example.com)에서 가져온 리소스에 접근할 하는 것을 차단
- 출처 A(ex:
- SOP 정책은 웹 브라우저에서 기본적으로 제공되며, 웹 개발자가 명시적으로 설정할 필요는 없다.
Origin(https://www.example.com) | 비교 |
|---|---|
https://www.example.com/about | 동일 출처 |
https://www.example.com/about?q=query | 동일 출처 |
https://abc.example.com | 교차 출처 |
http://www.example.com | 교차 출처 |
https://www.example.com:8080 | 교차 출처 |
- 동일 출처와 교차 출처의 기준은 프로토콜, Host(도메인), Port 동일 여부이다. 이중 하나라도 Origin과 다르면 그 URL은 교차출처로 인식된다.
- 두 URL의 프로토콜, 호스트, 포트가 모두 같아야 동일한 출처로 인정되며 웹 사이트를 샌드박스화 하여 잠재적인 보안 위협으로부터 보호해주는 정책이다.
Q. 왜 다른 출처 간의 상호 작용을 차단할까?
SOP 정책이 없는 상황이라고 가정해보자.
- 사용자가 악의적인
JavaScript가 포함되어 있는 페이지 (ex:service.example.com) 에 접속한다. - 사용자가 악성 페이지에 (ex:
service.example.com) 접속하여 악의적인JavaScript가 실행된다. - 악성 페이지 (ex:
service.example.com)는 사용자가 모르는 사이에 다른 사이트 (ex:portal.example.com)에 임의의 요청을 보내어, 사용자의 개인 정보(사용자 IP 등)를 탈취할 수 있다.
- SOP 장점: CSRF, XSS 같은 보안 취약점 공격으로 부터 안전하다.
- SOP 단점: 제한된 정책 때문에 외부에서 데이터를 불러오지 못한다.
CORS(Cross Origin Resource Sharing)
교차 출처 리소스 공유
- 보안도 중요하지만 기능 상 어쩔 수 없이 다른 도메인에 있는 리소스에 접근해야 하는 경우가 발생한다.
- 이러 경우를 대비 하기 위해 SOP의 예외 정책으로 CORS 정책이 만들어졌다. CORS를 사용하면 SOP의 제약을 받지 않는다.
- CORS의 요청 방식에는 크게 2가지 방식이 있다.
Simple RequestPreflight Request
Simple Request
Simple Request 조건
- HTTP Method 가
GET,POST,HEAD중 하나 - Content Type 이
application/x-www-form-urlencoded,multipart/form-data,text/plain중 하나 CORS-safelisted request-header를 포함하는 경우XMLHttpRequest.upload에 이벤트 핸들러, 리스너가 등록되지 않은 경우ReadableStream객체가 포함되지 않은 경우
Simple Request 동작 방식
- 클라이언트가 요청 헤더에 자신의
Origin을 실어서 서버로 요청 - 서버는 요청 메시지 헤더의
Origin을 확인한다 - CORS 요청이 유효하다면 서버는 응답 헤더에
Access-Control-Allow-Origin헤더를 추가해 사용자에게 응답한다.
service.example.com->api.example.com사이트의 리소스를 가져오기 위해 JavaScript에서 HTTP 요청 메시지를 전송한다.
<html>
〈head〉
〈title> test〈/title>
</head>
〈body>
〈div id="result">
</div>
〈script>
httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if(this status == 200 && this.readystate == this.DONE) {
document.getElementById("result").innerHTML = httpRequest.responseText;
};
httpRequest.open('GET', 'http://api.example.com/api/v1/test');
httpRequest.send();
〈/script>
</body>
〈/html〉- HTTP 요청 메시지는 아래와 같이 전송된다.
GET /api/v1/test HTTP/1.1
Host: api. example.com
User-Agent : Mozilla/5.0 (windows NT 10.0; Win64; x64) Applewebkit/537.36 (KHTML, 1ike Ge
cko) Chrome/88.0.4324.190 Safari/537.36
Accept: text/html, application/xhtml+xml, application/xmljq=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Origin: https://service.example.comservice.example.com 사이트의 프로토콜, 호스트, 포트 정보가 Origin 헤더를 통해 전송된다.
- 서버는 HTTP 요청 메시지의 Origin 헤더를 보고 어느 사이트를 통해 요청 메시지가 전송되었는지 확인할 수 있다. 해당 요청에 대한 HTTP 응답 메시지는 아래와 같다.
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
Transter-Encoding: chunked
Content-Type: application/xml서버는 Access-Control-Allow-Origin 헤더를 통해 응답해야 한다.
Access-Control-Allow-Origin: *= 모든 도메인에서 접근을 허용한다.Access-Control-Allow-Origin: https://service.example.com=https://service.example.com의 요청에서만 리소스에 대한 접근을 허용한다.
만약 Access-Control-Allow-Origin 헤더가 없거나, 해당 헤더에 명시된 출처가 요청을 보낸 페이지의 출처와 일치하지 않는 경우, 브라우저는 SOP 정책에 따라 응답을 차단한다.
Preflight Request
Simple Request의 조건을 만족하지 못할시 브라우저가 자동으로 생성한다Simple Request와 달리OPTIONS메서드를 통해 다른Origin의 리소스로 HTTP 요청을 미리 보내(preflight) 실제 요청이 전송하기에 안전하지 확인한다- 브라우저는 안전하다고 판단되면 이를 통해 실제 요청을 보낸다. CORS 요청의 경우, 유저 데이터에 영향을 줄 수 있기 때문에 이와 같이 미리 전송한다
요청 헤더
Origin- 현재 자신의 URL 정보를 포함
Access-Control-Request-MethodPreflight Request에서 사용되며 어떤 Method를 사용할지 서버에게 알리기 위해 사용되는 헤더(POST, GET, DELETE 등이 포함)
Access-Control-Request-HeadersPreflight Request에서 사용되며 어떤 Header를 사용할 것인지 서버에게 알리기 위해 사용되는 헤더 (X-PINGOTHER, Content-Type 등이 포함)
Access-Control-Request-* 헤더의 경우 실제 POST 요청시에는 포함되지 않고 OPTIONS 요청시에만 사용된다.
응답 헤더
Access-Control-Allow-Origin- 브라우저가 해당
Origin이 리소스에 접근 가능하도록 허용할 때 사용되는 헤더 *로 설정할 경우 브라우저는credentials옵션이 없는 요청에 한해 모든Origin이 해당 리소스에 접근 가능하도록 허용
- 브라우저가 해당
Access-Control-Allow-MethodsPreflight Request에 대해 리소스에 접근할 때 허용되는Method를 지정하기 위해 사용되는 헤더 (POST, GET, OPTIONS, *)
Access-Control-Allow-Headers- Preflight Request에 대해 해당 요청에서 사용할 수 있는 Header를 지정하기 위해 사용되는 헤더 (X-PINGOTHER, Content-Type 등)