도메인, 또는 포트가 다른 서버의 자원을 요청하는 매커니즘
HTTP:80
, HTTPS:443
으로 기본적으로 정해져 있기 때문)보안상의 이유로, 브라우저는 스크립트에서 시작한 CORS 요청을 제한한다.
Simple Request -> Preflight 를 트리거하지 않는 일부 요청
Preflight Request -> 사전 전송, 안전한지 확인
Credential Request -> 인증정보를 포함한 요청
1) 브라우저 : 요청 헤더에 Origin 이라는 필드에 요청을 보내는 출처를 함께 담아 보냄
Origin : https://velog.io/
2) 서버 : 해당 요청에 대한 응답시 응답 헤더의 Access-Control-Allow-Origin 이라는 필드에 리소스를 접근하는 것이 허용된 출처를 내려줌
3) 브라우저 : 보냈던 요청의 Origin과 서버가 보내준 응답의 Access-Control-Allow-Origin를 비교하여 유효성 체크
GET
/ HEAD
/ POST
중 하나의 메서드application/x-www-form-urlencoded
,multipart/form-data
, text/plain
만 가능!)XMLHttpRequest.upload
프로퍼티를 사용하여 접근ReadableStream
객체가 사용되지 않음GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
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
Transfer-Encoding: chunked
Content-Type: application/xml[…XML Data…]
Access-Control-Request-*
는 실제 POST 요청에서는 사용되지 않음!!
먼저 OPTIONS 메서드를 통해 다른 도메인의 리소스로 HTTP 요청을 보내 실제 요청이 전송하기에 안전한지 확인
Cross-site 요청은 유저 데이터에 영향을 줄 수 있기 때문에 이와같이 미리 전송(preflighted)하는 것
동작 예시
1) 사용자가 js 의 fetch
API 로 브라우저에게 리소스를 받아오라는 명령 내림
2) 브라우저 -> 서버 : 예비 요청
OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
Origin
에 대한 정보 + 이후 보낼 본 요청에 대한 정보Access-Control-Reqeust-Headers
: 본 요청에서 사용할 Headers
Access-Control-Request-Method
: 본 요청에서 사용할 Method
3) 서버 -> 브라우저 : 예비 요청에 대한 응답으로 자신이 허용, 금지하고 있는 것들에 대한 정보를 응답 헤더에 담아서 보내줌
HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Access-Conrol-Allow-Origin
: 해당 리소스에 접근 가능한 출처- 요청한 Origin 과 다를 경우, CORS 정책을 위반했다고 판단
- 판단 시점은 예비 요청에 대한 응답을 받은 이후이기 때문에 예비 요청의 성공 여부와는 상관X
4) 브라우저 : 보낸 예비 요청과 서버에서 받은 허용 정책 비교 후, 요청 안전 판단 -> 안전하다면 같은 엔드포인트로 본 요청을 보냄
5) 서버 : 본 요청에 대한 응답
6) 브라우저 : 최종적으로 해당 응답 데이터를 js 에게 넘겨줌
Access-Control-Allow-Origin
에는 *를 사용할 수 없으며, 명시적인 URL이어야한다.Access-Control-Allow-Credentials: true
가 존재해야한다.webpack-dev-server 라이브러리의 프록시 기능 사용
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'https://api.evan.com',
changeOrigin: true,
pathRewrite: { '^/api': '' },
},
}
}
}
서버에서 cross-origin HTTP 요청 허가
1) Access-Control-Allo-Origin response
헤더 추가
app.get('/data', (req, res) => {
res.header("Access-Control-Allow-Origin", "*");
res.send(data);
});
2) node.js 의 미들웨어 CORS 추가 패키지참고
npm install --save cors
yarn add cors
/* 모든 요청에 대한 허가 - 보안 취약 가능성*/
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors()); // CORS 미들웨어 추가
/* CORS 옵션 설정 */
const corsOptions = {
origin: 'http://localhost:3000', // 허락하고자 하는 요청 주소
credentials: true, // true -> 설정한 내용을 response 헤더에 추가
};
app.use(cors(corsOptions)); // config 추가
크롬 익스텐션 / Whale 익스텐션 개발시 api 요청을 해야 할 때 겪은 에러
깃헙이슈기록 참고
manifest
파일에 permission 값을 추가해주면 된다{
...
"permissions":[
"http://www.google.com/",
"https://www.google.com/"
],
...
}