지긋지긋한 CORS 오류 해결하기(with Proxy)

Mincho·2023년 5월 11일
2

cs지식

목록 보기
7/9

🔴 프론트와 백엔드가 통신하면서...

웹 개발을 하게 되면 프론트와 백엔드 통신을 하는 과정에서 위와 같은 에러를 확인할 수 있다. API콜을 하면 CORS정책에 막혔다는 에러가 뜨면서 통신이 되지 않는다. 왜 이런 문제가 발생하는지 알아보고 해결책도 살펴보자



🟠 CORS는 뭐고 왜 발생하는거야..??

CORS(Cross-Origin Resource Sharing)의 줄임말로 웹 애플리케이션에서 다른 도메인의 리소스를 요청할 때 발생하는 보안 정책이다.

 일단 위와 같은 url주소의 구성을 알아야 할 피요가 있다. CORS 오류를 이해하는데는 앞의 세가지 scheme(프로토콜), Domain Name, Port다. 이것이 곧 Origin(출처)이다. 이 구조를 파악하고 출처 정책에 대해 알아보자.

동일 출처 정책 (Same-Origin Policy)

 Same-Origin Policy는 동일한 출처에 대한 정책을 말한다. 한 마디로 동일한 출처를 가진 사이트끼리만 리소스를 공유할 수 있다는 것을 의미한다. 이런 정책을 하는 이유는 해커가 악의적으로 리소스를 가져오는 것을 방지하기 위해 시행하고 있다. 사전에 해킹에 대해 방지하는 것이다.

 앞에서 설명했듯이 Origin(출처)의 구조가 모두 동일한 url을 가지고 있다면 동일 출처로 간주하여 처리하고 있다. https에서 http리소스를 요청한다던지 도메인 이름이 서로 다른곳에서 요청을 하면 Same-origin 정책을 위반하여 CORS오류가 발생하게 되는 것이다.
그런데 이 정책을 위반하면 개발환경에서 어떻게 처리해주어야 하는 것일까..?

교차 출처 리소스 공유 (Cross-Origin Resource Sharing)

 Cross-Origin Resource Sharing은 다른 출처의 리소스 공유에 대한 허용을 할 수 있게 하는 정책이다. 해킹과 보안을 신경써야하는 부분은 당연하지만 개발환경에서 다른 출처 간의 통신을 허용해야하는 부분도 간과해서는 안된다.
그렇기 때문에 SOP정책을 위반하면서 CORS 정책에 따르면서 다른 출처의 리소스를 허용해야 한다는 것을 의미한다.

🟡 그럼 어떻게 처리를 해야 할까?

나의 경우 백엔드 django서버와 프론트엔드react서버가 통신을 하고 있었다. 이 경우를 예시로 보겠다.

백엔드 DJANGO

pip install django-cors-headers

처음에 djnago-cors-headers를 설치해준다.

INSTALLED_APPS =[
...

'corsheaders', # CORS 관련 추가

]

MIDDLEWARE = [

	'corsheaders.middleware.CorsMiddleware',     # CORS 관련 추가
...  
]

CORS_ORIGIN_WHITELIST = ['http://127.0.0.1:3000'
                         ,'http://localhost:3000']
CORS_ALLOW_CREDENTIALS = True

다음과 같이 django settings.py에 위와 같이 추가를 해준다.
CORS_ORIGIN_WHITELIST에는 통신을 허용할 url을 입력해준다.

React앱

fetch("https://example.com:1234/users/", {
	method: "POST",
	credentials: "include", // 클라이언트와 서버가 통신할때 쿠키와 같은 인증 정보 값을 공유하겠다는 설정
    body: JSON.stringify({
        userId: 1,
    }),
})

// axios 라이브러리
axios.post('https://example.com:1234/users/login', { 
    profile: { username: username, password: password } 
}, { 
	withCredentials: true // 클라이언트와 서버가 통신할때 쿠키와 같은 인증 정보 값을 공유하겠다는 설정
})

 백과 통신을 할때 credentials 옵션을 사용하여 인증 정보를 포함한 요청을 하여 CORS오류를 해결 할 수 있다. 이렇게 설정하면 브라우저는 쿠키 및 기타 인증 관련 헤더를 요청과 함께 전송하게 된다. 서버에서는 이러한 인증 정보를 확인하고 요청을 처리할 수 있다.

또 다른 방법(front)

프론트에서 proxy서버를 설정하여 CORS오류를 우회할 수도 있다. 프록시 서버는 네트워크 서비스에 간접적으로 접속하여 통신할 수 있게 해주는 서버를 의미한다. 클라이언트는 프록시 서버에 요청을 보내고, 프록시 서버는 실제 요청을 서버에 전달하고 응답을 클라이언트에게 다시 전달하는 구조이다.

npm i http-proxy-middleware

npm을 이용해 다음 라이브러리를 설치해준다.

다음과 같은경로에 setupProxy.js파일을 만들어준 뒤

const { createProxyMiddleware } = require("http-proxy-middleware");

module.exports = function (app) {
  app.use(
    createProxyMiddleware("/api/v1", {
      target: "https://backend.example.site",
      changeOrigin: true,
    })
  );
};

위와 같이 통신하고자하는 url을 target에 넣어주면 된다.
이후 API콜을 할 때는

const instance = axios.create({
  baseURL: "/api/v1/",
  headers: {
    "X-CSRFToken": Cookie.get("csrftoken") || "",
  },
  withCredentials: true,
});

export const postSignUp = (signUpInform) =>
  instance.post(`/users/`, signUpInform).then((res) => res.data);

이런식으로 url을 엔드포인트만 입력해주면 된다.



👉 후기

프로젝트 진행시 흔히 발생하고 있는 문제이다. 서버를 배포하기 전이나 배포한 후나 상황이 언제든지 달라질 수 있기 때문에 이 점을 유의하고 조치를 취해줘야 한다!!

👍올바른 피드백은 언제든지 환영입니다~!

참고자료

https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-CORS-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-%F0%9F%91%8F
https://evan-moon.github.io/2020/05/21/about-cors/

profile
사진찍는 개발자.

0개의 댓글