: 현재 페이지의 출처가 아닌 다른 출처로부터 온 데이터를 읽지 못하게 하는 브라우저의 보안 메커니즘
: 현재 페이지와 동일한 출처
: 현재 페이지와 다른 출처
: SOP의 제한을 받지 않고 Cross Origin의 데이터를 처리 할 수 있도록 해주는 메커니즘
: 현재 페이지의 출처가 아닌 다른 출처로부터 온 데이터를 읽지 못하게 하는 브라우저의 보안 메커니즘
: 현재 페이지와 동일한 출처
: 현재 페이지와 다른 출처
ex) https://same-origin.com/
1) https://same-origin.com/frame.html
: Same Origin(Path만 다름)
2) http://same-origin.com/frame.html
: Cross Origin(Scheme이 다름)
3) https://cross.same-origin.com/frame.html/
: Cross Origin(Host가 다름)
4) https://same-origin.com:1234/
: Cross Origin(Prot가 다름)
window.open
: 새로운 창 띄우는 함수
object.location.href
:객체가 가리키고 있는 URL 주소를 읽어오는 코드
- ex1)
이미지, 자바스크립트, CSS 등의 리소스는 SOP에 구애 받지 않고 외부 출처에 대해 접근 허용- ex2)
특정 포털 사이트가 카페, 블로그, 메일 서비스를 다음과 같이 운영하는 경우
https://cafe.sitename.com
: 카페
https://blog.sitename.com
: 블로그
https://mail.sitename.com
: 메일
https://sitename.com
: 메인
-> 사용자가 받은 메일 개수를 메인에 출력하려면
-> SOP 적용받지 않고 리소스 공유할 방법 필요
=> CORS(Cross Origin Resource Sharing; 교차 출처 리소스 공유)
CORS 헤더 방식에서 HTTP 메소드 중 OPTIONS를 통해 수신측 웹 리소스의 접근 관련 질의를 하는 과정
CORS preflight 이후 :
1> 브라우저가 수신측의 응답이 발신측의 요청과 상응하는지 확인
2> POST 요청 보냄 : 수신 측의 웹 리소스를 요청하는 HTTP 요청을 보냄
/*
XMLHttpRequest 객체를 생성합니다.
XMLHttpRequest는 웹 브라우저와 웹 서버 간에 데이터 전송을
도와주는 객체 입니다. 이를 통해 HTTP 요청을 보낼 수 있습니다.
*/
xhr = new XMLHttpRequest();
/* https://theori.io/whoami 페이지에 POST 요청을 보내도록 합니다. */
xhr.open('POST', 'https://theori.io/whoami');
/* HTTP 요청을 보낼 때, 쿠키 정보도 함께 사용하도록 해줍니다. */
xhr.withCredentials = true;
/* HTTP Body를 JSON 형태로 보낼 것이라고 수신측에 알려줍니다. */
xhr.setRequestHeader('Content-Type', 'application/json');
/* xhr 객체를 통해 HTTP 요청을 실행합니다. */
xhr.send("{'data':'WhoAmI'}");
OPTIONS /whoami HTTP/1.1
Host: theori.io
Connection: keep-alive
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: https://dreamhack.io
Accept: */*
Referer: https://dreamhack.io/
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://dreamhack.io
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type
Header | 설명 |
---|---|
Access-Control-Allow-Origin | 헤더 값에 해당하는 Origin에서 들어오는 요청만 처리 |
Access-Control-Allow-Methods | 헤더 값에 해당하는 메소드의 요청만 처리 |
Access-Control-Allow-Credentials | 쿠키 사용 여부를 판단
: 예시의 경우 쿠키의 사용을 허용 |
Access-Control-Allow-Headers | 헤더 값에 해당하는 헤더의 사용 가능 여부를 나타냄 |
: 메시지를 주고받기 위한 이벤트 핸들러를 이용해 리소스를 공유
ex)
https://dreamhack.io
var testWindow = window.open('http://test.dreamhack.io');
window.addEventListener('message', function (e) {
if (e.origin === 'http://test.dreamhack.io') {
console.log(e.data); // 'bye'
}
});
testWindow.postMessage('hello', 'http://test.dreamhack.io');
http://test.dreamhack.io
window.addEventListener('message', function (e) {
if (e.origin === 'https://dreamhack.io') {
console.log(e.data); // 'hello'
e.source.postMessage('bye', 'https://dreamhack.io');
}
});
: 다른 오리진이 허용하는 설정 등을 HTTP 헤더를 통해 확인한 후 허용하는 요청을 보내 리소스를 공유
https://dreamhack.io
에서 https://test.dreamhack.io/me
에 대해 요청
-> HTTP Request에서 OPTIONS헤더를 통해 메소드, 헤더 등이 허용하는지 확인
https://dreamhack.io
xhr = new XMLHttpRequest();
xhr.open('POST', 'https://test.dreamhack.io/me');
xhr.withCredentials = true;
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send("{'data':'hello world!'}");
HTTP Request
OPTIONS /me HTTP/1.1
Host: test.dreamhack.io
Connection: keep-alive
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: https://dreamhack.io
Accept: */*
Referer: https://dreamhack.io/
HTTP Response
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://dreamhack.io
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type
: 스크립트 태그를 통해 다른 오리진의 리소스를 요청하고, 응답 데이터를 현재 오리진의 Callback 함수에서 다루는 방식으로 리소스를 공유
: 스크립트 태그를 통해 외부 자바스크립트 코드를 호출하면 현재 오리진에서 해당 코드가 실행된다는 점을 이용한 방식
이미지, 자바스크립트, CSS 등의 리소스는 SOP에 구애 받지 않고 외부 출처에 대해 접근을 허용
-><script>
태그로 Cross Origin의 데이터를 불러옴
<script>
태그 내에서는 데이터를 자바스크립트 코드로 인식
-> Callback 함수! 활용해야
<script>
태그와 callback함수를 이용Cross Origin에 요청시,
callback 인자에 어떤 함수로 받아오는 데이터를 핸들링할지 넘김
대상 서버는 전달된 Callback으로 데이터 감싸 응답
https://dreamhack.io
<script>
function myCallback(data){
console.log(data.id) // 'dreamhack'
}
</script>
<script src='http://test.dreamhack.io/me?callback=myCallback'></script>
http://test.dreamhack.io/me?callback=myCallback
myCallback({'uid':1, 'id':'dreamhack', 'pw':'********'});
<script>
/* myCallback이라는 콜백 함수를 지정합니다. */
function myCallback(data){
/* 전달받은 인자에서 id를 콘솔에 출력합니다.*/
console.log(data.id)
}
</script>
<!--
https://theori.io의 스크립트를 로드하는 HTML 코드입니다.
단, callback이라는 이름의 파라미터를 myCallback으로 지정함으로써
수신측에게 myCallback 함수를 사용해 수신받겠다고 알립니다.
-->
<script src='http://theori.io/whoami?callback=myCallback'></script>
/*
수신측은 myCallback 이라는 함수를 통해 요청측에 데이터를 전달합니다.
전달할 데이터는 현재 theori.io에서 클라이언트가 사용 중인 계정 정보인
{'id': 'dreamhack'} 입니다.
*/
myCallback({'id':'dreamhack'});