What is SOP(Same Origin Policy)?
HTTP ์์ฒญ์์ ๊ฐ์ ธ์จ ์ ์์ ์ธ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ์ ์๊ฒ ํ๋ ๋ธ๋ผ์ฐ์ ๋ณด์
Origin ๊ตฌ๋ถ : Protocol, Port, Host
์ฃผ์๋ฅผ ๊ธฐ์ค์ผ๋ก Same Origin, Cross Origin ํ๋จ ์์
URL ๊ฒฐ๊ณผ ์ด์
https://same-origin.com/frame.html | Same Origin | Path๋ง ๋ค๋ฆ |
http://same-origin.com/frame.html | Cross Origin | Scheme์ด ๋ค๋ฆ |
https://cross.same-origin.com/frame.html | Cross Origin | Host๊ฐ ๋ค๋ฆ |
https://same-origin.com:1234/ | Cross Origin | Port๊ฐ ๋ค๋ฆ |
SOP Test
Origin์ด http://dreamhack.io์ธ SOP ๋ณดํธ ๊ธฐ๋ฒ์ด ๊ฑธ๋ ค์๋ ์ฌ์ดํธ์์ "window.open" ํจ์๋ฅผ ํตํด same origin์ธ ์ฌ์ดํธ์ cross origin ์ฌ์ดํธ๋ฅผ ์ง์ ์ด์ด๋ณด์.
Same Origin
sameNewWindow = window.open('https://dreamhack.io/lecture');
console.log(sameNewWindow.location.href);
๊ฒฐ๊ณผ: https://dreamhack.io/lecture
Cross Origin
crossNewWindow = window.open('https://theori.io');
console.log(crossNewWindow.location.href);
๊ฒฐ๊ณผ: Origin ์ค๋ฅ ๋ฐ์
๋ค๋ง, Cross Origin์ด read๋ ๋ถ๊ฐ๋ฅํ์ง๋ง Data์ write์ ๊ฐ๋ฅํ๋ค.
crossNewWindow = window.open('https://theori.io');
crossNewWindow.location.href = "https://dreamhack.io";
SOP Example
<iframe src="[Define Origin Site]" id="my-frame">
<script>
let myFrame = document.getElementById("my-frame");
myFrame.onload = () => {
try {
let secretValue = myFrame.contentWindow.document.getElementById('secret-element').innerText;
console.log({ secretValue });
} catch() {
...
}
const loadSameOrigin = () => { myFrame.src = 'https://same-origin.com/frame.html'; }
const loadCrossOrigin = () => { myFrame.src = 'https://cross-origin.com/frame.html'; }
</script>
<button onclick=loadSameOrigin()>Same Origin</button><br>
<button onclick=loadCrossOrigin()>Cross Origin</button>
<div id="secret-element">treasure</div>
iframe ํ๊ทธ์ src๋ฅผ ์ด์ฉํด Origin์ ์ง์ ํ๋ค. myFrame ๋ณ์์์ id๊ฐ "my-frame"์ธ Element๋ฅผ ์ ์ฅํ๊ณ , onload๋ฅผ ํจ์๋ฅผ ์คํ์ํจ๋ค. loadSameOrigin๊ณผ loadCrossOrigin ํจ์๋ฅผ ์คํ์ํค๋ฉด ๊ฐ๊ฐ ์๋์ ๊ฐ๋ค.
// Result
SameOrigin :
{"secretValue":"treasure"}
CrossOrigin :
{"error":{"stack":"Error: Blocked a frame with origin "https://same-origin.com/" from accessing a cross-origin frame.
at HTMLIFrameElement.myFrame.onload (https://same-origin.com/:6:51)"}}
What is CORS(Cross Origin Resource Sharing)?
HTTP ํค๋์ ๊ธฐ๋ฐํ์ฌ Cross Origin ๊ฐ์ Resource๋ฅผ ๊ณต์ ํ๋ ๋ฐฉ์. Sender ์ธก์์ CORS ํค๋๋ฅผ ์ค์ ํด ์์ฒญํ๋ฉด, Receiver ์ธก์์ ํค๋๋ฅผ ๊ตฌ๋ถํด ๊ท์น์ ๋ง๊ฒ Data๋ฅผ ๊ฐ์ ธ๊ฐ๋๋ก ์ค์ . ์ด ๊ณผ์ ์ ๋ง์น ํ, ๋ธ๋ผ์ฐ์ ๋ ์์ ์ธก์ ์๋ต์ด ๋ฐ์ ์ธก์ ์์ฒญ๊ณผ ์์ํ๋์ง ํ์ธํ๊ณ , ๊ทธ๋์ผ ๋น๋ก์ POST ์์ฒญ์ ๋ณด๋ด ์์ ์ธก์ ์น ๋ฆฌ์์ค๋ฅผ ์์ฒญํ๋ HTTP ์์ฒญ์ ๋ณด๋ธ๋ค.
Web Resource Request Code
/*
XMLHttpRequest ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค.
XMLHttpRequest๋ ์น ๋ธ๋ผ์ฐ์ ์ ์น ์๋ฒ ๊ฐ์ ๋ฐ์ดํฐ ์ ์ก์
๋์์ฃผ๋ ๊ฐ์ฒด ์
๋๋ค. ์ด๋ฅผ ํตํด HTTP ์์ฒญ์ ๋ณด๋ผ ์ ์์ต๋๋ค.
*/
xhr = new XMLHttpRequest();
xhr.open('POST', 'https://theori.io/whoami');
/* HTTP ์์ฒญ์ ๋ณด๋ผ ๋, ์ฟ ํค ์ ๋ณด๋ ํจ๊ป ์ฌ์ฉํ๋๋ก ํด์ค๋๋ค. */
xhr.withCredentials = true;
xhr.setRequestHeader('Content-Type', 'application/json');
/* xhr ๊ฐ์ฒด๋ฅผ ํตํด HTTP ์์ฒญ์ ์คํํฉ๋๋ค. */
xhr.send("{'data':'WhoAmI'}");
Sender's HTTP Request
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/
Server's 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
Types of CORS's Header
Header Description
Access-Control-Allow-Origin | ํค๋ ๊ฐ์ ํด๋นํ๋ Origin์์ ๋ค์ด์ค๋ ์์ฒญ๋ง ์ฒ๋ฆฌํฉ๋๋ค. |
Access-Control-Allow-Methods | ํค๋ ๊ฐ์ ํด๋นํ๋ ๋ฉ์๋์ ์์ฒญ๋ง ์ฒ๋ฆฌํฉ๋๋ค. |
Access-Control-Allow-Credentials | ์ฟ ํค ์ฌ์ฉ ์ฌ๋ถ๋ฅผ ํ๋จํฉ๋๋ค. ์์์ ๊ฒฝ์ฐ ์ฟ ํค์ ์ฌ์ฉ์ ํ์ฉํฉ๋๋ค. |
Access-Control-Allow-Headers | ํค๋ ๊ฐ์ ํด๋นํ๋ ํค๋์ ์ฌ์ฉ ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ๋ํ๋ ๋๋ค. |
Reasons for use
SOP ๋ณดํธ ๊ธฐ๋ฒ์ ๊ตฌ์ ๋ฐ์ง ์๊ณ ์ธ๋ถ ์ถ์ฒ์ ๋ํ ์ ๊ทผ์ ํ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ์กด์ฌ. ํ๊ทธ๋ก๋ <img>, <style>, <script>๊ฐ ์๊ณ ๊ทธ ์ธ์๋ ์๋น์ค์์ ๋์ผ ์ถ์ฒ ์ ์ฑ ์ธ SOP๋ฅผ ์ํํ์ฌ ๋ค๋ฅธ ์ถ์ฒ์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌ ํด์ผ ํ๋ ๊ฒฝ์ฐ๋ ์๋ค. ๋ฐ๋ผ์ CORS ๋ณดํธ ๊ธฐ๋ฒ์ ์ด์ฉํ๋ค.