교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다. - MDN
⇒ 브라우저에서 다른 출처의 리소스를 공유하는 방법
Protocol
+ host
+ port
origin이 모두 같은 것
같은 출처에서만 리소스를 공유할 수 있다는 규칙
브라우저에서 다른 서버에서 요청할 경우에 해당되고, 브라우저를 거치지 않고 서버 간 통신을 할 경우에는 이 정책이 적용되지 않음
🔒 통신에 아무런 제약이 없다면 악의적인 사용자가 소스코드를 보고 **CSRF, XSS**와 같은 방법을 이용하여 **정보를 탈취**할 수 있음서버에게 바로 요청을 보내는 방법
Access-Control-Allow-Origin
헤더를 포함한 응답을 브라우저에 보냄Access-Control-Allow-Origin
헤더를 확인해서 CORS 동작을 수행할지 판단GET
, HEAD
, POST
Authorization
불가능application/json
를 사용함서버에 예비 요청을 보내서 안전한지 판단 후 본 요청을 보내는 방법
OPTIONS
메서드를 통해 예비 요청을 보냄Access-Control-Allow-Origin
헤더를 포함한 응답을 브라우저에 보냄Access-Control-Allow-Origin
헤더를 확인해서 CORS 동작을 수행할지 판단서버측 응답에서 접근 권한을 주는 헤더를 추가하여 해결
// server source
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*"); // 모든 도메인
res.header("Access-Control-Allow-Origin", "https://example.com"); // 특정 도메인
});
const cors = require("cors");
const app = express();
app.use(cors());
아무 옵션없이 설정하면 모든 cross-origin 요청에 대해 응답이므로,
특정 도메인이나 특정 요청에만 응답하게 옵션을 설정하는 것이 좋음
const options = {
origin: "http://example.com", // 접근 권한을 부여하는 도메인
credentials: true, // 응답 헤더에 Access-Control-Allow-Credentials 추가
optionsSuccessStatus: 200, // 응답 상태 200으로 설정
};
app.use(cors(options));
app.get("/example/:id", cors(), function (req, res, next) {
res.json({ msg: "example" });
});
// 프록시 쓰지 않았을때
// localhost:8080(클라이언트 측) --X (CORS)--> domain.com (서버 측)
// 프록시를 설정 후
// localhost:8080(클라이언트 측) --O 프록시가 설정된 Webpack Dev Server--> domain.com (서버 측)
module.exports = {
devServer: {
proxy: {
"/api": {
target: "domain.com",
changeOrigin: true,
},
},
},
};
중간의 프록시 서버 덕분에, domain.com 서버에서는 같은 도메인(domain.com)에서 온 요청으로 인식하여 CORS 에러가 발생하지 않는다.
create-react-app 으로 생성한 프로젝트에서는, package.json 에 proxy 값을 설정하여 proxy 기능을 활성화 하는 방법도 있다.
{
//...
"proxy": "http://localhost:4000"
}
Json with padding으로 각기 다른 도메인에 상주하는 서버로부터 데이터를 요청하기 위해 사용
Json은 경량의 Data 교환 형식인데 다른 도메인에서 Json 데이터를 가져올 때 Javascript에서 SOP 정책으로 인해 데이터를 못 가져오는 경우가 발생
⇒ Json Data를 callback 함수에 넣어서 전송하는 Jsonp을 사용
<!-- Frontend -->
<!DOCTYPE html>
<html>
<script>
function fn (data) {
console.log(data) // data
}
</script>
<script
type="application/javascript"
src="http://localhost:3001/cors?callback=fn"
>
</script>
</html>-
// Backend
router.get('/cors', (req, res, next) => {
res.send(`${req.query.callback}('data')`)
})
jsonp가 가능한 이유
웹 브라우저에서 실행되는 Javascript는 동일 출처 정책에 따라 XMLHttpRequest 등의 직접적인 Http 통신을 이용해 데이터를 가져오는 것은 불가능
그러나 HTML
Jsonp은
보안상 이슈 ⇒ 보통은 개발할 때 사용