cors란 Cross-Origin-Resource-Sharing의 약자입니다.
직역해보면 교차 출처 리소스 공유 정책인데 이는 서로 다른 출처(Origin)를 가진 주소로 요청이 들어왔을 때 발생할 수 있는 에러입니다.
출처란 우리가 어떤 사이트를 접속할 때 URL을 통해 접근하는데 이 URL은 크게
Protocol, Host, Port로 이루어져 있습니다.
https://www.naver.com:443/user?query=name&page=1#first
이 때 출처(Origin)는 : Protocol + Host + Port 로 3가지 중 하나라도 다르면 다른 출처로 인식됩니다.
sop(Same-Origin-Policy)는 cors의 반대로 같은 출처에서만 접근이 가능한 정책입니다.
보안을 위해서 세운 정책이지만 이러한 sop정책이 불편하다보니 cors가 나온것입니다.

같은 다음끼리와 네이버끼리는 요청이 가능하지만 네이버에서 다음 백엔드로 request 요청시 cors 허락이 안되어 있으면 거절됩니다. 브라우저에서 api requst를 보내기 전에 preflight 요청을 보내서 cors가 허용되는지 확인을 합니다. 그 후 허용되어 있으면 서버에서 허용되었다고 알려주고 브라우저에서 api요청을 보내지만 허용이 안되어 있으면 서버에서 cors 거절로 응답합니다. 그러면 브라우저에서 요청을 막아버립니다.

위에 요청을 보면 Preflight 요청 후 다시 요청을 보낸걸 알 수 있습니다.
즉 cors에러의 출처 비교와 차단은 서버에서 하는것이 아니라 브라우저에서 하는 것입니다.
이것을 다시 생각해보면 서버에서 서버로 요청을하면 문제없이 요청을 받을 수 있습니다.
이것을 프록시(Proxy)라고 합니다.

그렇다면 죄다 cors를 허용해버리면 편한데 왜 번거롭게 하는 것일까요?
cors는 브라우저를 보호하기 위한 정책입니다.
csrf(cross site request forgery) 공격 방지를 위한 것이죠.

만약 이렇게 네이버 로그인을 해서 쿠키에 로그인 증표를 가지고 있는 유저가 해커가 만든 네이버 짝퉁 페이지에 우연히 들어갔다고 해봅시다. 이런 경우 api 요청시 네이버 서버에서 클라이언트의 쿠키에 있는 로그인 증표를 확인 후 유저가 맞으면 api 수행후 응답을 하는데 이 때 쿠키에 있는 증표는 서버에서 발급받은 증표인게 확인이 되면 해당 서버에 요청을 할때 요청에 header에 들어가게 됩니다. 근데 cors가 모두 허용이 되어있으면 짝퉁 네이버에서 보낸 요청을 보낼떄 preflifht 요청에 허용되어있다고 할 것이고 잘못된 요청(Ex. 삭제 api)를 짝퉁 네이버에서 보내게 되면 쿠키에 있던 로그인 증표가 보내지게 되면서 서버에서는 로그인된 유저가 맞다는 판단을 하여 나도 모르게 게시물이 지워지거나 이상한 응답을 받게 될 수도 있습니다.

하지만 이렇게 cors 금지를 해놓으면 짝퉁 서버에서 요청을 보낼때 cors 금지 응답을 받고 짝퉁 네이버 브라우저에서 요청이 차단됩니다.

해커가 proxy서버를 만들어서 시도하려고 해도 네이버 백엔드가 아닌 해커의 서버로 요청을 한것이므로 로그인 증표가 보내지지 않습니다. 그러면 해커의 백엔드에서 네이버 백엔드로 api요청이 와도 로그인 부터 하라는 응답을 받죠.
프록시를 쓰는것도 방법중 하나이지만 일반적인 방법은 서버에서 Access-Control-Allow-Origin 헤더를 세팅하는 것입니다. 헤더에 작성된 출처만 브라우저가 리소스를 접근할 수 있도록 허용하는 것입니다.
var http = require('http');
const PORT = process.env.PORT || 3000;
var httpServer = http.createServer(function (request, response) {
// Setting up Headers
// response.setHeader('Access-Control-Allow-origin', '*'); // 모든 출처(orogin)을 허용 -> 보안이 허술
response.setHeader('Access-Control-Allow-origin', 'https://ㅜnaver.com');
response.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); // 모든 HTTP 메서드 허용
response.setHeader('Access-Control-Allow-Credentials', 'true'); // 클라이언트와 서버 간에 쿠키 주고받기 허용
// ...
response.writeHead(200, { 'Content-Type': 'text/plain' });
response.end('ok');
});
httpServer.listen(PORT, () => {
console.log('Server is running at port 3000...');
});