
SOP는 같은 출처의 리소스만 공유할 수 있음을 의미하는 동일 출처 정책이다.

여기서 동일한 출처란, 프로토콜, 호스트, 포트 까지 모두 일치하는 것을 의미한다.
SOP는 해킹 등의 위협으로 부터 안전한 보안상의 이점이 있기 때문에 모든 브라우저에서 기본적으로 사용하고 있는 정책이다. 또한 HTML이나 JavaScript의 fetch API 등은 기본적으로 SOP를 따른다. 하지만 개발을 할 때 다른 출처의 리소스를 사용하게 될 일은 너무나도 많고, 이런 문제 상황에서 등장하는 것이 바로 CORS 정책이다.
교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다. (MDN)
👉 교차 출처는 다른 출처로 이해하면 쉽다.

흔히 CORS 에러 라고 하는 이 에러는 사실 CORS 때문이 아니라 SOP 때문이다. 오히려 CORS는 이 에러를 해결해줄 수 있는 방안이다.
또한 CORS는 브라우저 스펙에 포함되는 정책이기 때문에, 브라우저를 통하지 않는 통신을 할 때는 이 정책이 적용되지 않는다.
우리가 CORS 정책을 위반하는 리소스 요청을 하더라도 서버가 같은 출처에서 보낸 요청만 받겠다는 로직을 가진 경우가 아닌 이상 서버는 정상적으로 응답을 하게 된다. 즉, 서버는 일단 요청을 받으면 어떤 요청이든 응답을 하고, 이후 브라우저가 CORS 정책 위반 여부를 판단한다. 서버가 보내준 응답 헤더에는 Access-Control-Allow-Origin 값이 포함되어 있는데, 이 값은 서버가 허가하는 출처를 포함한다. 브라우저는 서버가 허가하는 출처와 요청의 출처가 동일하면 리소스를 받아오고 다르면 응답을 버리고 CORS 에러를 출력한다.
CORS의 동작 방식에는 크게 3가지가 있다.
주로 사용하는 방식으로, 본 요청을 보내기 전에 브라우저 스스로 이 요청이 안전한지 확인하기 위해 보내는 사전 요청이다. 이 때, OPTIONS 메서드를 사용한다.

JavaScript의 fetch API를 사용해 브라우저에게 리소스를 받아오라는 명령을 내림 ➡ 브라우저가 서버에 사전 요청을 보냄 ➡ 서버는 어떤 것들을 허용하는지에 대한 정보를 응답 헤더에 담아서 브라우저에게 보냄 ➡ 브라우저는 미리 보낸 사전 요청과 서버의 응답을 비교한 후 안전하다고 판단되면 같은 엔드포인트로 다시 본 요청을 보냄 ➡ 서버가 응답하면 브라우저가 최종적으로 리소스를 JavaScript에 넘겨줌
프리플라이트와 동작 방식은 같고 사전 요청의 유무만 다르다. 단순 요청은 사전 요청 없이 그냥 바로 서버에 요청을 보낸다. 하지만 아무때나 단순 요청을 할 수 있는 것은 아니다. 특정 조건을 만족하는 경우에만 사전 요청을 생략할 수 있고, 사실상 조건이 까다로워서 충족하기 어렵다.
좀 더 보안을 강화하고 싶을 때 사용하는 방식으로, 요청 헤더에 인증 정보를 담아 보내는 요청이다. 출처가 다를 경우에는 별도의 설정을 하지 않으면 민감한 정보이기 때문에 쿠키를 보낼 수 없다. 이 경우에는 프론트와 서버 양측 모두 CORS 설정이 필요하다.
서버에서 Access-Control-Allow-Origin 헤더에 알맞은 값을 잘 세팅해주는 것이 좋다. 와일드카드인 *를 사용해서 셋팅하게 되면 모든 출처를 허가한다는 의미여서 편할 수는 있지만, 심각한 보안 이슈를 초래할 수 있기 때문에 가급적이면 출처를 명시하는 것이 좋다.
Node.js와 Express에서 CORS 설정 방법Node.js 서버Node.js로 간단한 HTTP 서버를 만들 경우, 다음과 같이 응답 헤더를 설정해줄 수 있다.
const http = require('http');
const server = http.createServer((request, response) => {
// 모든 도메인
response.setHeader("Access-Control-Allow-Origin", "*");
// 특정 도메인
response.setHeader("Access-Control-Allow-Origin", "https://codestates.com");
// 인증 정보를 포함한 요청을 받을 경우
response.setHeader("Access-Control-Allow-Credentials", "true");
})
Express 서버Express 프레임워크를 사용해서 서버를 만드는 경우에는, cors 미들웨어를 사용해서 보다 더 간단하게 CORS 설정을 해줄 수 있다.
const cors = require("cors");
const app = express();
//모든 도메인
app.use(cors());
//특정 도메인
const options = {
origin: "https://codestates.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" });
});
Reference)
CORS는 왜 이렇게 우리를 힘들게 하는걸까?