기업협업 인턴쉽 중 겪었던 오류인 CORS에러에 대해 설명하고,
나의 해결방법을 적어보고, 기록하고자 글을 쓰게 되었다.
CORS (Cross-Origin Resource Sharing) 에러는 웹 브라우저에서 발생하는 보안 관련 에러 중 하나이다. CORS는 웹 페이지가 다른 출처(origin)의 리소스(자원)를 요청할 때 발생하는 문제이다. 웹 브라우저는 보안상의 이유로 같은 출처에서만 리소스를 요청 할 수 있는데 이 때 말하는 출처란 프르토콜(http, https), 호스트(domain), 포트 번호를 의미한다.
출처가 다른 두 도메인이 데이터를 주고받는 일은 매우 위험한 일이다. 만약 CORS에러가 없다면 해커가 우리가 만들어놓은 어플리케이션에 악성코드를 심어놓아 개인정보를 탈취할 수도 있고, 위험한 상황에 놓이게 된다.
인턴쉽 당시 나는 나의 로컬에서 작업을 하고 있었고, 회사의 백엔드 서버는 이미 배포가 된 상태였다. 결국 나는 나의 로컬주소인 http://localhost:3000 에서 요청을 보내는 상태였고, 회사의 서버는 프로토콜, 호스트, 포트번호가 달랐기 때문에 CORS에러가 발생하였다.
클라이언트에서 http요청의 헤더에 Origin을 담아 전달
- http프르토콜 요청 헤더에 Origin이라는 필드에 출처를 담아서 전달
- 서버는 응답헤더에 Access-Control-Allow-Origin을 담아 클라이언트로 전달
- 클라이언트에서 Origin과 서버가 보내준 Access-Control-Allow-Origin을 비교
클라이언트에서 비교를 한 후, 유효하다면 문제 없이 다른 출처의 리소스를 가져오게 되고, 유효하지 않다면 CORS에러를 보내게 된다.
당시 회사의 백엔드 응답 헤더에 Access-Control-Allow-Origin이 존재하지 않았고, 당시 백엔드 개발자분이 계시지 않았기 때문에 나 혼자 해결해야 하는 상황이 되었다. CORS에러를 해결하기 위해 구글링을 하던 도중 http proxy middleware라는 라이브러리를 발견하게 되었고, CORS에러를 우회할 수 있다는 글을 보고 http proxy middleware를 공부하게 되었다.
http Proxy Middleware는 HTTP 요청을 프록시 하는 미들웨어 라이브러리이다. 이 라이브러리를 사용하면 클라이언트에서 서버로 요청하는 HTTP요청을 중간에 가로채서 프록시 서버로 요청을 보내고 프록시 서버에서 받은 응답을 클라이언트로 보내는 방식으로 동작한다. 이를 통해 클라이언트에서 직접 요청하는 것과는 다른 동작을 수행할 수 있다.
- 프록시란 ?
프록시(Proxy)는 컴퓨터 네트워크에서 다른 네트워크 서비스에 대한 중개자 역할을 하는 컴퓨터 시스템 또는 응용 프로그램을 의미한다.
프록시는 클라이언트와 서버 사이에서 중개자 역할을 하며, 클라이언트가 서버에 직접적으로 요청하지 않고 프록시를 통해 요청을 보내면, 프록시가 요청을 대신 처리하고 결과를 클라이언트에게 반환한다.
npm i http-proxy-middleware
//setUpProxy.js
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
createProxyMiddleware("/payment/token", {
target: "API 주소",
changeOrigin: true,
})
);
app.use(
createProxyMiddleware("/payment/find", {
target: "API 주소",
changeOrigin: true,
})
);
app.use(
createProxyMiddleware("/payment/import", {
target: "API 주소",
changeOrigin: true,
})
);
};
createProxyMiddleware : api의 엔드포인트를 적는 곳이다.
target : api의 엔드포인트가 아닌 출처만 명시하는 곳이다.
changeOrigin : 호스트 헤더의 출처를 대상 URL로 변경 하는지 여부이다. CORS 처리를 위해 출처를 수정해주어야 한다. 기본값은 false이다.
//payment.js
axios({
method: "post",
url: "/payment/import",
data: formData,
headers: { "Content-Type":"multipart/form-data" },
})
axios({
url: `/payment/find?imp_uid=${rsp.imp_uid}`,
method: "GET",
headers: { "Content-Type": "application/json" },
})
요청 url에 엔드포인트만 적어주면 된다.
이러한 방법들 모두 로컬서버 즉, 개발할때만 사용이 가능하다. 실제 배포 할 때에는 서버 응답헤더에 Access-Control-Allow-Origin을 해주는 것이 좋을 것 같다는 생각이 든다.