๊ต์ฐจ ์ถ์ฒ ๋ฆฌ์์ค ๊ณต์ (CORS)
๋ฑ์ฅ ๋ฐฐ๊ฒฝ
๋์ผ ์ถ์ฒ ์ ์ฑ (SOP: Same-Origin Policy)
์๋ ๋๋ฉ์ธ์ด ๋ค๋ฅด๋ฉด ์์ฒญ์ ์ฃผ๊ณ ๋ฐ์ ์ ์๊ฒ ํ๋ ค๋ ๊ฒ ์น๋ธ๋ผ์ฐ์ ์ ์ฃผ์ ์ ์ฑ ์ด์๋ค. ๋์ผ์ถ์ฒ์ ์ฑ ์ ์ด๋ค ์ถ์ฒ(origin)์์ ๋ถ๋ฌ์จ ๋ฌธ์๋ ์คํฌ๋ฆฝํธ๊ฐ ๋ค๋ฅธ ์ถ์ฒ์์ ๊ฐ์ ธ์จ ๋ฆฌ์์ค์ ์ํธ์์ฉํ๋ ๊ฒ์ ์ ํํ๋ ์ค์ํ ๋ณด์ ๋ฐฉ์์ด๋ค, ์ถ์ฒ๊ฐ ๊ฐ๋ค๋ ๊ฒ์ ๋ URL์ ํ๋กํ ์ฝ, ํธ์คํธ, ํฌํธ ์ธ ๊ฐ๊ฐ ๊ฐ๋ค๋ ๊ฒ์ ๋งํ๋ค.
ํฌ๋ก์ค ๋๋ฉ์ธ (Cross Domain) ์ด์
๊ทธ๋ฌ๋ ์ ์ ์น์ฌ์ดํธ์์ ํ ์ ์๋ ์ผ์ด ๋ง์์ง๋ฉด์ ๋ฌธ์ ๊ฐ ์๊ฒผ๋ค. Ajax๊ฐ ๋์ค๊ณ Open API๊ฐ ํ๋ฐํด์ง๋ฉด์ ์น์ด ๋จ์ ๋ฌธ์๊ฐ ์๋๋ผ ์ดํ๋ฆฌ์ผ์ด์ ์ด ๋์๋ค. ์ด๋ ์๋ฐ์คํฌ๋ฆฝํธ(XMLHttpRequest)๋ก ๋ค๋ฅธ ์นํ์ด์ง์ ์ ๊ทผํ ๋ ๋ค๋ฅธ ์ถ์ฒ์ ํ์ด์ง์๋ ์ ๊ทผํด์ผ ํ ํ์์ฑ์ด ์๊ฒผ๋ค.
์ฆ, SOP๋ฅผ ์ฐํํด์ ์๋ก ๋ค๋ฅธ ๋๋ฉ์ธ ๊ฐ์ ํต์ ์ ํ ์ ์๊ฒ ํด์ค ๋ฌด์ธ๊ฐ๊ฐ ํ์ํ๊ฒ ๋์๋ค. ๋ฐ๋ผ์ JSONP, Reverse Proxy, Flash Socket์ ์ฐํ ๋ฐฉ๋ฒ์ด ์๊ฒจ๋๊ฒ ๋์๋ค.
CORS์ ๋ฑ์ฅ
์น๋ธ๋ผ์ฐ์ ์ ์ฅ์์๋ ์ด ์ฐํ๋ก๋ฅผ ๊ทธ๋ฅ ๋๊ธฐ์๋ ๋ณด์์์ ๋ฌธ์ ๊ฐ ์ปค์ง๊ณ , ๋ง์๋ CORS์ ๋ํ ์์๊ฐ ๋๋ฌด ๋ง์๋ค. ๋ฐ๋ผ์ ํฌ๋ก์ค ๋๋ฉ์ธ ์ด์๋ฅผ ํด๊ฒฐํ ํ์ค์ ํ์์ฑ์ด ๋๋๋์๋ค.
- ์ด์ W3C์์ ๊ถ์ฅ์ฌํญ์ผ๋ก CORS ์ฌ์์ ๋ฐํํ๊ฒ ๋์๋ค.
- ํ์ฌ ํ๋ฐํ๊ฒ ์ ์ง ๊ด๋ฆฌ๋๋ ์ฌ์์ WHATWG์ Fetch Living Standard
CORS(Cross-Origin Resource Sharing)๋?
- ์ถ๊ฐ HTTP ํค๋๋ฅผ ์ฌ์ฉํ์ฌ ํ ์ถ์ฒ์์ ์คํ ์ค์ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ค๋ฅธ ์ถ์ฒ์ ์ ํํ ์์์ ์ ๊ทผํ ์ ์๋ ๊ถํ์ ๋ถ์ฌํ๋๋ก ๋ธ๋ผ์ฐ์ ์ ์๋ ค ์ฃผ๋ ์ฒด์ ์ด๋ค.
- ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฆฌ์์ค๊ฐ ์์ ์ ์ถ์ฒ(๋๋ฉ์ธ, ํ๋กํ ์ฝ, ํฌํธ)์ ๋ค๋ฅผ ๋ ๊ต์ฐจ์ถ์ฒ HTTP ์์ฒญ์ ์คํํ๋ค.
- CORS ์ฒด์ ๋ ๋ธ๋ผ์ฐ์ ์ ์๋ฒ ๊ฐ ์์ ํ ๊ต์ฐจ ์ถ์ฒ ์์ฒญ ๋ฐ ๋ฐ์ดํฐ ์ ์ก์ ์ง์ํ๋ค.
- SOP๋ฅผ ๋ฐ๋ฅด๋ XMLHttpRequest์ Fetch API๋ฅผ ์ฌ์ฉํ๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ค๋ฅธ ์ถ์ฒ์ ๋ฆฌ์์ค๋ฅผ ๋ถ๋ฌ์ค๋ ค๋ฉด ๊ทธ ์ถ์ฒ์์ ์ฌ๋ฐ๋ฅธ CORS ํค๋๋ฅผ ํฌํจํ ์๋ต์ ๋ฆฌํดํด์ผ ํ๋ค.
- CORS๋ฅผ ์ฌ์ฉํ๋ ์์ฒญ
- XMLHttpRequest, Fetch API ํธ์ถ
- ์น ํฐํธ
- WebGL ํ ์ค์ฒ
drawImage()
๋ฅผ ์ฌ์ฉํด ๊ทธ๋ฆฐ ์ด๋ฏธ์ง/๋น๋์ค ํ๋ ์- ์ด๋ฏธ์ง๋ก๋ถํฐ ์ถ์ถํ๋ CSS Shapes
- ์ด ์ด์ธ์ ์์ฒญ์ ํ๋ฝํ์ง ์๋๋ค.
CORS ์์ฒญ ์ข ๋ฅ
๊ฐ๋จํ ์์ฒญ(Simple Request)
- ๊ธฐ์กด ๋ฐ์ดํฐ์ ๋ถ์์ฉ์ ์ผ์ผํค์ง ์๋ ์์ฒญ
- CORS ์ฌ์ ์์ฒญ์ ๋ฐ์์ํค์ง ์๋ ์์ฒญ
- ์กฐ๊ฑด
- GET, HEAD, POST ์ค ํ ๊ฐ์ง ๋ฐฉ์์ ์ฌ์ฉํ๋ค.
- Custom Header ๋ถํฌํจ
- ์์ธ) Fetch ๋ช ์ธ์์ CORS-safelisted request-header๋ก ์ ์ํ ํค๋์ ๊ฒฝ์ฐ ์๋์ผ๋ก ์ค์ ํ ์ ์๋ค.
- POST์ผ ๊ฒฝ์ฐ Content-Type์ด ์๋ ์
์ค ํ๋๋ฅผ ๋ง์กฑ
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- ๋ชจ๋ ๋๋ฉ์ธ ์์ฒญ ๋ฆฌ์์ค ์ ๊ทผ ํ์ฉ:
Access-Control-Allow-Origin: *
- ํน์ ๋๋ฉ์ธ์ ์์ฒญ๋ง ๋ฆฌ์์ค ์ ๊ทผ ํ์ฉ:
Access-Control-Allow-Origin: ํ๋ฝ๋๋๋ฉ์ธ๋ช
์ฌ์ ์์ฒญ(Preflighted Request)
- ๋ณธ ์์ฒญ์ ๋ณด๋ด๊ธฐ ์ ์ ์ฌ์ ์์ฒญ์ ๋ณด๋ด์ ์๋ฒ๊ฐ ์ด์ ์๋ต์ด ๊ฐ๋ฅํ ์ง ํ์ธํ๋ ๋ฐฉ๋ฒ์ด๋ค. Cross-site์์ฒญ์ ์ ์ ๋ฐ์ดํฐ์ ์ํฅ์ ์ค ์ ์๊ธฐ ๋๋ฌธ์ ๋ฏธ๋ฆฌ ์ ์ก(preflighted)ํ์ฌ ์ค์ ์์ฒญ์ด ์ ์กํ๊ธฐ์ ์์ ํ ์ง ํ์ธํ ์ ์๋ค.
- ์ฌ์ ์์ฒญ์ ๋ณด๋ด๋ ๊ฒฝ์ฐ
- GET, HEAD, POST ์ด์ธ์ ์์ฒญ
- Custom Header ํฌํจ
- POST ์์ฒญ์ผ ๊ฒฝ์ฐ Content-Type์ด ์๋ ์
์ ๋ง์กฑํ์ง ์์ ๋
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- ์ฌ์ ์์ฒญ ๊ณผ์
- ๋์ผํ URL์ OPTIONS method๋ก ์์ฒญ(Preflight)
OPTIONS
: ์๋ฒ์์ ์ถ๊ฐ ์ ๋ณด๋ฅผ ํ๋ณํ๋ ๋ฐ ์ฌ์ฉํ๋ HTTP/1.1 ๋ฉ์๋์ด๋ค. safe๋ฉ์๋์ด๊ธฐ ๋๋ฌธ์, ๋ฆฌ์์ค๋ฅผ ๋ณ๊ฒฝํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ค.OPTIONS ์์ฒญ๊ณผ ํจ๊ป ๋ ๊ฐ์ ๋ค๋ฅธ ์์ฒญ ํค๋๊ฐ ์ ์ก๋๋ค.
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
- ์์ฒญ์ ๋ํด ์๋ฒ์์๋ ํ์ฉ๋๋ method, ํ์ฉํ๋ ํค๋, ์ฟ ํค ํ์ฉ ์ฌ๋ถ๋ฅผ ์๋ต
- ์๋ฒ๊ฐ ์์ฒญ์ ํ์ฉํ๋ค๋ฉด ๋ณธ ์์ฒญ์ ๋ณด๋ธ๋ค.
preflighted request ์ดํ ๋ฆฌ๋ค์ด๋ ํธ๋ฅผ ์ง์ํ์ง ์๋ ๋ธ๋ผ์ฐ์ ๋์ฒ๋ฐฉ์
- preflight ๋ฆฌ๋ค์ด๋ ํธ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ์๋ฒ์ธก ๋์ ๋ณ๊ฒฝ
- preflight๋ฅผ ๋ฐ์์ํค์ง ์๋ simple request๊ฐ ๋๋๋ก ์์ฒญ ๋ณ๊ฒฝ
์ธ์ฆ์ ๋ณด๋ฅผ ํฌํจํ ์์ฒญ(Request with Credentials)
- ๊ธฐ๋ณธ์ ์ผ๋ก cross-sitew XMLHttpRequest๋ Fetchํธ์ถ์์ ๋ธ๋ผ์ฐ์ ๋ ์๊ฒฉ ์ฆ๋ฉฐ์์ ๋ณด๋ด์ง ์๋๋ค. XMLHttpRequest ๊ฐ์ฒด๋ Request ์์ฑ์๊ฐ ํธ์ถ๋ ๋ ํน์ ํ ํ๋๊ทธ๋ฅผ ์ค์ ํด์ผ ํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
const invocation = new XMLHttpRequest();
const url = 'http://bar.other/resources/credentialed-content/';
function callOtherDomain() {
if (invocation) {
invocation.open('GET', url, true);
// ํ๋๊ทธ
invocation.withCredentials = true;
invocation.onreadystatechange = handler;
invocation.send();
}
}
์์ฒญ์ ์ฟ ํค๋ฅผ ํฌํจํ๊ณ ์ถ๋ค๋ฉด
XMLHttpRequest
๊ฐ์ฒด์withCredential
ํ๋กํผํฐ ๊ฐ์ true๋ก ์ค์ ํ๋ค.ํ์ฉํ๋ค๋ฉด ์๋ฒ ์ธก์
Access-Control-Allow-Credentials
์๋ต ํค๋๋ฅผtrue
๋ก ์ค์ ํ๋ค.credentials request์ ์๋ตํ ๋๋ Access-Control-Allow-Originํค๋์ ๋ฐ๋์ ๊ฐ์ ์ง์ ํด์ผ ํ๋ค. ์์ผ๋ ์นด๋(
*
)๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๋๋ค. ์์ผ๋ ์นด๋์ผ ๊ฒฝ์ฐ ์์ฒญ์ด ์คํดํ๋ค.
HTTP ์๋ต ํค๋
Access-Control-Allow-Origin
: ๋จ์ผ ์ถ์ฒ๋ฅผ ์ง์ ํ์ฌ ๋ธ๋ผ์ฐ์ ๊ฐ ํด๋น ์ถ์ฒ๊ฐ ๋ฆฌ์์ค์ ์ ๊ทผํ๋๋ก ํ์ฉ๋๋ค. credentials request ์๋ ๊ฒฝ์ฐ ์์ผ๋ ์นด๋๋ฅผ ์ฌ์ฉํด ๋ธ๋ผ์ฐ์ ์ origin์ ์๊ด ์์ด ๋ชจ๋ ๋ฆฌ์์ค์ ์ ๊ทผํ๋๋ก ํ์ฉํ ์ ์๋ค.Access-Control-Expose-Headers
: ๋ธ๋ผ์ฐ์ ๊ฐ ์ ๊ทผํ ์ ์๋ ํค๋๋ฅผ ์๋ฒ์ ํ์ดํธ๋ฆฌ์คํธ์ ์ถ๊ฐAccess-Control-Max-Age
: preflight request ์์ฒญ ๊ฒฐ๊ณผ๋ฅผ ์บ์ํ ์ ์๋ ์๊ฐ ์ง์ Access-Control-Allow-Credentials
: credentials request ํ์ฉ ์ฌ๋ถ ์ง์ Access-Control-Allow-Methods
: ๋ฆฌ์์ค์ ์ ๊ทผํ ๋ ํ์ฉ๋๋ ๋ฉ์๋ ์ง์ Access-Control-Allow-Headers
: preflight request ์์ฒญ ์ ์ฌ์ฉํ ์ ์๋ HTTP ํค๋ ์ง์
HTTP ์์ฒญ ํค๋
Origin
: cross-site ์ ๊ทผ ์์ฒญ ๋๋ preflight request์ ์ถ์ฒ๋ก, ์ ๊ทผ ์ ์ด ์์ฒญ ์ ํญ์ ์ ์ก๋๋ค.Origin: ์์ฒญ์์๋์๋ฒURL
Access-Control-Request-Method
: ์ค์ ์์ฒญ์์ ์ด๋ค HTTP ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ง ์๋ฒ์๊ฒ ์๋ ค์ฃผ๊ธฐ ์ํด preflight requestํ ๋ ์ฌ์ฉ๋๋ค.Access-Control-Request-Headers
: ์ค์ ์์ฒญ์์ ์ด๋ค HTTP ํค๋๋ฅผ ์ฌ์ฉํ ์ง ์๋ฒ์๊ฒ ์๋ ค์ฃผ๊ธฐ ์ํด preflight requestํ ๋ ์ฌ์ฉ๋๋ค.
cross-site XMLHttpRequest ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์๋ ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์์ผ๋ก cross-origin ๊ณต์ ์์ฒญ ํค๋๋ฅผ ์ค์ ํ ํ์ ์๋ค.
์ฐธ์กฐ
- https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
- https://youtu.be/yTzAjidyyqs
- https://en.wikipedia.org/wiki/Cross-origin_resource_sharing