Access-Control-Allow-Origin ํค๋ ์๋ฒฝ ๊ฐ์ด๋
CORS ์ค๋ฅ์ ์์ธ์ธ Access-Control-Allow-Origin ํค๋๋ฅผ ์๋ฒฝํ ์ดํดํ๊ณ ํด๊ฒฐํ์ธ์. ๋ฌธ๋ฒ, ๋ณด์, Nginx/Node.js ์ค์ ์์๊น์ง ๋ค๋ฃน๋๋ค.
์น ๊ฐ๋ฐ์ ํ๋ค ๋ณด๋ฉด ํ ๋ฒ์ฏค์ ์ฝ์์์ CORS error๋ผ๋ ๋ฌด์๋ฌด์ํ ๋ฉ์์ง๋ฅผ ๋ง์ฃผํ๊ฒ ๋ฉ๋๋ค. ์ด ์ค๋ฅ๋ ๋๋ถ๋ถ ๋ค๋ฅธ ์ถ์ฒ(origin)์ ๋ฆฌ์์ค๋ฅผ ์์ฒญํ ๋ ๋ฐ์ํ๋๋ฐ์, ๋ฐ๋ก ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ์ด์ ๊ฐ Access-Control-Allow-Origin ํค๋์ ์์ต๋๋ค.
์ด ๊ธ์์๋ ๊ต์ฐจ ์ถ์ฒ ๋ฆฌ์์ค ๊ณต์ (CORS)์ ํต์ฌ์ธ Access-Control-Allow-Origin ํค๋๊ฐ ๋ฌด์์ธ์ง, ์ด๋ป๊ฒ ๋์ํ๋์ง, ๊ทธ๋ฆฌ๊ณ ์ค์ ์๋ฒ ํ๊ฒฝ์์๋ ์ด๋ป๊ฒ ์ค์ ํด์ผ ํ๋์ง ์์ธํ ์์๋ณด๊ฒ ์ต๋๋ค. ์ด ๊ธ์ ๋๊น์ง ์ฝ์ผ์๋ฉด CORS ์ค๋ฅ์ ์์ ๊ฐ ์๊ฒ ๋์ฒํ ์ ์์ ๊ฑฐ์์!
Access-Control-Allow-Origin ์ด๋ ๋ฌด์์ธ๊ฐ์?
Access-Control-Allow-Origin์ HTTP ์๋ต ํค๋ ์ค ํ๋์
๋๋ค. ์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์๊ฒ "์ด ์๋ต์ ํน์ ์ถ์ฒ(origin)์ ๊ณต์ ํด๋ ๊ด์ฐฎ์"๋ผ๊ณ ์๋ ค์ฃผ๋ ์ญํ ์ ํ์ฃ .
์น ๋ธ๋ผ์ฐ์ ๋ ๋ณด์์์ ์ด์ ๋ก '๋์ผ ์ถ์ฒ ์ ์ฑ
(Same-Origin Policy)'์ ๋ฐ๋ฆ
๋๋ค. ์ด ์ ์ฑ
์ ๊ธฐ๋ณธ์ ์ผ๋ก ์คํฌ๋ฆฝํธ๊ฐ ์์ ์ด ๋ก๋๋ ์ถ์ฒ์ ๋ค๋ฅธ ์ถ์ฒ์ ๋ฆฌ์์ค์ ์ํธ์์ฉํ๋ ๊ฒ์ ๋ง์ต๋๋ค. ์๋ฅผ ๋ค์ด, https://my-awesome-site.com์์ ์คํ๋๋ ์คํฌ๋ฆฝํธ๋ https://api.another-site.com์ API๋ฅผ ์ง์ ํธ์ถํ ์ ์์ต๋๋ค.
ํ์ง๋ง ํ๋ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ์ฌ๋ฌ ์๋น์ค์ API๋ฅผ ํธ์ถํ๋ ๋ฑ ๋ค๋ฅธ ์ถ์ฒ์ ๋ฆฌ์์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ํ์์ ์
๋๋ค. ์ด๋ ํ์ํ ๊ฒ์ด ๋ฐ๋ก ๊ต์ฐจ ์ถ์ฒ ๋ฆฌ์์ค ๊ณต์ (Cross-Origin Resource Sharing, CORS) ๋ฉ์ปค๋์ฆ์ด๋ฉฐ, Access-Control-Allow-Origin ํค๋๋ ์ด ๋ฉ์ปค๋์ฆ์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ด๊ณ ์ค์ํ ๋ถ๋ถ์
๋๋ค.
CORS์ ๋์ ๋ฐฉ์์ ๊ฐ๋จํฉ๋๋ค.
- ๋ธ๋ผ์ฐ์ ๊ฐ ๋ค๋ฅธ ์ถ์ฒ๋ก HTTP ์์ฒญ์ ๋ณด๋ผ ๋, ์์ฒญ ํค๋์
Originํ๋์ ์์ฒญ์ ๋ณด๋ด๋ ์ถ์ฒ๋ฅผ ๋ด์ ๋ณด๋ ๋๋ค. - ์์ฒญ์ ๋ฐ์ ์๋ฒ๋ ์ด ์์ฒญ์ ํ์ฉํ ์ง ๊ฒฐ์ ํ๊ณ , ์๋ต ํค๋์
Access-Control-Allow-Originํ๋์ ์ ๊ทผ์ ํ์ฉํ๋ ์ถ์ฒ๋ฅผ ๋ช ์ํ์ฌ ์๋ตํฉ๋๋ค. - ์๋ต์ ๋ฐ์ ๋ธ๋ผ์ฐ์ ๋ ์์ ์ด ๋ณด๋ธ ์์ฒญ์
Origin๊ฐ๊ณผ ์๋ฒ๊ฐ ๋ณด๋ด์คAccess-Control-Allow-Origin๊ฐ์ ๋น๊ตํฉ๋๋ค. ๋ ๊ฐ์ด ์ผ์นํ๋ฉด ๋ฆฌ์์ค๋ฅผ ์ ์์ ์ผ๋ก ๋ก๋ํ๊ณ , ์ผ์นํ์ง ์์ผ๋ฉด CORS ์ค๋ฅ๋ฅผ ๋ฐ์์ํค๋ฉฐ ๋ฆฌ์์ค๋ฅผ ์ฐจ๋จํฉ๋๋ค.
๋ฌธ๋ฒ๊ณผ ์ฌ์ฉ๋ฒ
Access-Control-Allow-Origin ํค๋๋ ๋ค์๊ณผ ๊ฐ์ ์ธ ๊ฐ์ง ์ฃผ์ ๊ฐ์ ๊ฐ์ง ์ ์์ต๋๋ค.
Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: <origin>
Access-Control-Allow-Origin: null
๊ฐ ๊ฐ์ด ์ด๋ค ์๋ฏธ๋ฅผ ๊ฐ์ง๋์ง ์์ธํ ์ดํด๋ณด์ฃ .
* (์์ผ๋์นด๋)
๊ฐ์ฅ ๊ฐ๋จํ ์ค์ ๋ฐฉ๋ฒ์
๋๋ค. *๋ "๋ชจ๋ ์ถ์ฒ์์ ์ค๋ ์์ฒญ์ ํ์ฉํ๋ค"๋ ์๋ฏธ์
๋๋ค. ์ด๋ค ๋๋ฉ์ธ์์๋ ๋ด ์๋ฒ์ ๋ฆฌ์์ค์ ์ ๊ทผํ ์ ์๊ฒ ๋์ฃ .
Access-Control-Allow-Origin: *
๊ฐ๋ฐ ์ด๊ธฐ ๋จ๊ณ๋ ๊ณต๊ฐ API์ฒ๋ผ ์ถ์ฒ์ ์๊ด์์ด ๋๊ตฌ๋ ์ ๊ทผํ ์ ์๋ ๋ฆฌ์์ค๋ฅผ ์ ๊ณตํ ๋ ์ ์ฉํฉ๋๋ค. ํ์ง๋ง ์ธ์ฆ ์ ๋ณด(credentials)๊ฐ ํฌํจ๋ ์์ฒญ์๋ *๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ ์ค์ํ ์ ์ฝ์ด ์์ต๋๋ค. ์ฟ ํค๋ ์ธ์ฆ ํค๋๋ฅผ ์ฌ์ฉํ๋ ์์ฒญ์ *๋ก ์๋ตํ๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ๋ณด์ ์ค๋ฅ๋ฅผ ๋ฐ์์ํต๋๋ค.
<origin> (ํน์ ์ถ์ฒ)
๊ฐ์ฅ ์์ ํ๊ณ ๊ถ์ฅ๋๋ ๋ฐฉ๋ฒ์
๋๋ค. https://my-awesome-site.com๊ณผ ๊ฐ์ด ๋ฆฌ์์ค ์ ๊ทผ์ ํ์ฉํ ์ ํํ ์ถ์ฒ๋ฅผ ๋ช
์ํฉ๋๋ค.
Access-Control-Allow-Origin: https://developer.mozilla.org
์ด๋ ๊ฒ ์ค์ ํ๋ฉด https://developer.mozilla.org์์ ๋ณด๋ธ ์์ฒญ์ ๋ํด์๋ง ๋ฆฌ์์ค๋ฅผ ๊ณต์ ํ๊ณ , ๊ทธ ์ธ ๋ค๋ฅธ ๋ชจ๋ ์ถ์ฒ์ ์์ฒญ์ ๋ธ๋ผ์ฐ์ ์ ์ํด ์ฐจ๋จ๋ฉ๋๋ค. ํ๋์ ์ถ์ฒ๋ง ๋ช
์ํ ์ ์์ผ๋ฏ๋ก, ์ฌ๋ฌ ์ถ์ฒ๋ฅผ ํ์ฉํด์ผ ํ๋ค๋ฉด ์๋ฒ ์ธก์์ ์์ฒญ์ Origin ํค๋ ๊ฐ์ ํ์ธํ๊ณ ํ์ฉ ๋ชฉ๋ก์ ์๋ ๊ฐ์ผ๋ก ๋์ ์ผ๋ก ์ค์ ํด์ฃผ์ด์ผ ํฉ๋๋ค.
null
null ๊ฐ์ ์ฝ๊ฐ ํน์ํ ๊ฒฝ์ฐ์ ์ฌ์ฉ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ก์ปฌ ํ์ผ(file://)์์ ์์ฒญ์ ๋ณด๋ด๊ฑฐ๋ ๋ฆฌ๋ค์ด๋ ํธ๊ฐ ๋ฐ์ํ๋ ๊ฒฝ์ฐ Origin ํค๋ ๊ฐ์ด null์ด ๋ ์ ์์ต๋๋ค. ํ์ง๋ง ๋ณด์์ null์ ๋ช
์์ ์ผ๋ก ํ์ฉํ๋ ๊ฒ์ ๋งค์ฐ ์ ์คํด์ผ ํฉ๋๋ค.
ํํ ๊ฒช๋ ๋ฌธ์ ์ ํด๊ฒฐ ๋ฐฉ๋ฒ
CORS ๊ด๋ จ ๋ฌธ์ ์ค ๊ฐ์ฅ ํํ ๊ฒ์ ์ธ์ฆ ์ ๋ณด(credentials)๊ฐ ํฌํจ๋ ์์ฒญ์ด ์คํจํ๋ ๊ฒฝ์ฐ์ ๋๋ค.
fetch API๋ XMLHttpRequest๋ฅผ ์ฌ์ฉํ ๋ credentials: 'include' ์ต์
์ ์ฃผ๋ฉด ์ฟ ํค๋ ์ธ์ฆ ํค๋์ ๊ฐ์ ์ธ์ฆ ์ ๋ณด๋ฅผ ์์ฒญ์ ๋ด์ ๋ณด๋ผ ์ ์์ต๋๋ค. ํ์ง๋ง ์ด ๊ฒฝ์ฐ, ์๋ฒ๋ ๋ค์๊ณผ ๊ฐ์ ๊ท์น์ ๋ฐ๋์ ์ง์ผ์ผ ํฉ๋๋ค.
Access-Control-Allow-Originํค๋ ๊ฐ์ผ๋ก*์์ผ๋์นด๋๋ฅผ ์ฌ์ฉํด์๋ ์ ๋ฉ๋๋ค. ๋ฐ๋์ ์์ฒญ์ ๋ณด๋ธ ํน์ ์ถ์ฒ๋ฅผ ๋ช ์ํด์ผ ํฉ๋๋ค.Access-Control-Allow-Credentials: trueํค๋๋ฅผ ์๋ต์ ํฌํจํด์ผ ํฉ๋๋ค. ์ด ํค๋๊ฐ ์์ผ๋ฉด ๋ธ๋ผ์ฐ์ ๋ ์ธ์ฆ ์ ๋ณด๊ฐ ํฌํจ๋ ์๋ต์ ๊ฑฐ๋ถํฉ๋๋ค.
๋ง์ฝ ์๋ฒ๊ฐ ์์ผ๋์นด๋(*)๋ฅผ ์ฌ์ฉํ๋ฉด์ ์ธ์ฆ์ ํ์ฉํ๋ ค๊ณ ํ๋ฉด, ๋ธ๋ผ์ฐ์ ๋ ์ด ์๋ต์ ์ ํจํ์ง ์์ ๊ฒ์ผ๋ก ๊ฐ์ฃผํ๊ณ ์ค๋ฅ๋ฅผ ๋ฐ์์ํต๋๋ค. ๋ฐ๋ผ์ ์ธ์ฆ์ด ํ์ํ API๋ฅผ ๊ฐ๋ฐํ ๋๋ ๋ฐ๋์ ํ์ฉํ ์ถ์ฒ๋ฅผ ๋ช
ํํ๊ฒ ์ง์ ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
๋ณด์ ๊ณ ๋ ค์ฌํญ
Access-Control-Allow-Origin: * ์ค์ ์ ํธ๋ฆฌํ์ง๋ง, ๋ณด์ ์ธก๋ฉด์์๋ ์ ์ฌ์ ์ธ ์ํ์ ์๊ณ ์์ต๋๋ค. ์ด ์ค์ ์ ์
์์ ์ธ ์ฌ์ดํธ๋ฅผ ํฌํจํ ๋ชจ๋ ์ถ์ฒ๊ฐ ์ฌ๋ฌ๋ถ์ ์๋ฒ ๋ฆฌ์์ค์ ์ ๊ทผํ ์ ์๋๋ก ํ์ฉํ๊ธฐ ๋๋ฌธ์
๋๋ค.
์๋ฅผ ๋ค์ด, ๋ด๋ถ์์๋ง ์ฌ์ฉํด์ผ ํ๋ API๋ฅผ *๋ก ์ค์ ํด๋๋ฉด ์ธ๋ถ์์ ํด๋น API๋ฅผ ๋ฌด๋จ์ผ๋ก ํธ์ถํ์ฌ ์ ๋ณด๋ฅผ ํ์ทจํ๊ฑฐ๋ ์๋ฒ์ ๋ถ๋ด์ ์ค ์ ์์ต๋๋ค.
๋ฐ๋ผ์ ํ๋ก๋์ ํ๊ฒฝ์์๋ ๋ค์๊ณผ ๊ฐ์ ๋ณด์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๋ ๊ฒ์ด ์ข์ต๋๋ค.
- ํ์ฉ ๋ชฉ๋ก(Allowlist) ์ฌ์ฉ: ๋ฆฌ์์ค ์ ๊ทผ์ด ํ์ํ ์ถ์ฒ๋ค์ ๋ฏธ๋ฆฌ ์ ์ํด๋๊ณ , ์๋ฒ๋ ์์ฒญ์
Originํค๋๊ฐ ์ด ๋ชฉ๋ก์ ํฌํจ๋ ๊ฒฝ์ฐ์๋ง ํด๋น ์ถ์ฒ๋ฅผAccess-Control-Allow-Origin๊ฐ์ผ๋ก ์ค์ ํ์ฌ ์๋ตํฉ๋๋ค. - ์ต์ ๊ถํ์ ์์น: ๊ผญ ํ์ํ ์ถ์ฒ์๋ง ์ ๊ทผ์ ํ์ฉํ๊ณ , ๊ฐ๋ฅํ๋ฉด
*์ฌ์ฉ์ ํผํ์ธ์.
์๋ฒ ์ค์ ์์
์ค์ ์๋ฒ ํ๊ฒฝ์์ Access-Control-Allow-Origin ํค๋๋ฅผ ์ด๋ป๊ฒ ์ค์ ํ๋์ง Nginx์ Node.js(Express)์ ์์๋ฅผ ํตํด ์์๋ณด๊ฒ ์ต๋๋ค.
Nginx ์ค์ ์์
Nginx์์๋ add_header ์ง์์ด๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ๊ฒ ํค๋๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.
1. ๋ชจ๋ ์ถ์ฒ ํ์ฉ (๋น๊ถ์ฅ)
# nginx.conf
location / {
add_header 'Access-Control-Allow-Origin' '*';
# ... ๋ค๋ฅธ ์ค์ ๋ค
}
2. ํน์ ์ถ์ฒ๋ง ํ์ฉ (๊ถ์ฅ)
# nginx.conf
location / {
add_header 'Access-Control-Allow-Origin' 'https://your-domain.com';
add_header 'Vary' 'Origin'; # ์บ์ฑ ๊ด๋ จ ์ด์๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ์ถ๊ฐ
# ... ๋ค๋ฅธ ์ค์ ๋ค
}
์๋ฒ๊ฐ ํน์ ์ถ์ฒ๋ฅผ ์๋ต์ผ๋ก ๋ณด๋ผ ๋๋, ์๋ต์ด Origin ์์ฒญ ํค๋์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์์ ํด๋ผ์ด์ธํธ์ ์ค๊ฐ ์บ์ ์๋ฒ์ ์๋ ค์ฃผ๊ธฐ ์ํด Vary: Origin ํค๋๋ฅผ ํจ๊ป ๋ณด๋ด๋ ๊ฒ์ด ์ข์ต๋๋ค.
Node.js (Express) ์ค์ ์์
Express ํ๋ ์์ํฌ์์๋ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ ์๋ต์ CORS ํค๋๋ฅผ ์ฝ๊ฒ ์ถ๊ฐํ ์ ์์ต๋๋ค. cors์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ํธ๋ฆฌํ์ง๋ง, ์ง์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1. ๋ชจ๋ ์ถ์ฒ ํ์ฉ (๋น๊ถ์ฅ)
// app.js
const express = require('express');
const app = express();
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
// ํ์ํ ๋ค๋ฅธ CORS ํค๋๋ค (Access-Control-Allow-Methods ๋ฑ)
next();
});
// ... ๋ผ์ฐํธ ์ค์
2. ํน์ ์ถ์ฒ๋ง ํ์ฉ (๊ถ์ฅ)
// app.js
const express = require('express');
const app = express();
const allowedOrigins = ['http://localhost:3000', 'https://your-domain.com'];
app.use((req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
res.setHeader('Access-Control-Allow-Credentials', 'true');
// ... ํ์ํ ๋ค๋ฅธ CORS ํค๋๋ค
next();
});
// ... ๋ผ์ฐํธ ์ค์
๋ ๋์ ์น์ ์ํ ์ฒซ๊ฑธ์
CORS์ ๋์ ์๋ฆฌ๋ฅผ ์ ํํ ์ดํดํ๊ณ ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ํ๋ ๊ฒ์ ์์ ํ๊ณ ํจ์จ์ ์ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋๋ ๊ฐ๋ฐ์์ ๊ธฐ๋ณธ ์์์ด๋ผ๊ณ ํ ์ ์์ต๋๋ค. ์ค๋ ๋ฐฐ์ด ๋ด์ฉ์ ๋ฐํ์ผ๋ก ์ฌ๋ฌ๋ถ์ ํ๋ก์ ํธ์์ CORS ์ค์ ์ ๋ค์ ํ๋ฒ ์ ๊ฒํด๋ณด๊ณ , ๋ ์์ ํ ์น ์๋น์ค๋ฅผ ๋ง๋ค์ด๋๊ฐ์๊ธธ ๋ฐ๋๋๋ค!