-
❎ CORS에 관하여IT 2025. 6. 20. 18:08
Back-end나 Front-end만 공부를 하다가 두 개를 서로 연결하거나, 단순한 요청에서는 멀쩡하다가 정보를 담아서 보내는 순간 CORS 에러를 접하게됩니다. 본 포스팅에서 CORS란 무엇이고, 어떻게 동작하는지, 오류의 기준은 무엇인지, 어떻게 해결하는지 알아보도록 하겠습니다.
🤔CORS란? Cross Origin Resource Sharing
단순히 해석하자면 서로 다른 Origin 끼리 자원을 공유하는 것 이라는 의미이고 실제로도 그런 의미이다. CORS를 에러로 접한 분들이 많아 CORS는 에러다! 라고 생각하실 수도 있다.
🤔💭Origin이란?
그렇다면 Origin이란 무엇인가? 모든 홈페이지는 URL로 구성되어 있으며, 어디 출처인지를 나타내는 URL의 영역이 Origin이다. 아래 그림과 같이 Origin은 세 가지 영역을 합쳐 출처를 구분하는 Key와 같은 역할을 한다.
어떤 출처인지를 나타내는 URL의 영역 Origin 즉, CORS는 서로 다른 출처를 가진 곳끼리 요청할 때를 위한 정책입니다. 예를 들어 비행기를 타고 해외를 나갈 때, 육고기 소시지는 금지되어 있고 생선 소시지는 통과되는 것과 같이 서로 다른 출처 끼리 무엇을 주고 받을지 정합니다. 물론 국내에서는 무엇이 오가든 제한을 두지 않으며 이를 SOP(Single Origin Policy)라고 합니다.
🤷 어떻게 동작하고 어디서 오류가 발생하는가?
출처가 다른 곳으로 요청을 보낼 시, CORS 정책을 확인하고 정책에 위반될 경우 오류를 반환합니다.이를 이해가기 위해서 '브라우저'와 '서버' 두 가지 주체로 나누었습니다.
Client(사용자)가 다른 출처에 요청을 보낼 때, 브라우저는 다른 출처(서버)에게 요청을 바로 보내지 않고 해당 요청을 어떻게할지 잠시 고민합니다. 이때, 요청을 총 세가지 유형으로 나누어 서버에 요청을 보냅니다.
서버에 요청을 보내기전 검사하는 브라우저 1️⃣ Simple Request(단순 요청)
브라우저가 생각 했을 때, 단순 요청인 경우에는 출처가 다르더라도 바로 요청을 보내버립니다. 외국을 방문할 때, 검증되고 특이사항이 없는 국가인 경우에 비자를 발급하지 않고 무비자로 가는 경우와 같습니다. 이러한 단순 요청은 형식이 정해져있어 다른 출처에 자원을 수정 or 회손 하는 경우가 적은 경우 입니다. 조건은 아래 세 가지를 모두 만족해야 합니다.
단순 요청으로 판단해 바로 서버에 보내고 응답 받음 - Method
GET, POST, HEAD인 경우 - 추가 헤더
Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width인 경우 - Content-Type
2번에서 Content-Type의 경우 아래 세 가지만 허용합니다.
- text/plain
단순히 String을 담은 요청의 경우
ex) body : "this is text"
- multipart/form-data
이미지 같이 Form을 이용해 데이터를 넣어 보내는 경우
- application/x-www-form-urlencoded
URL에 명시되는 경우
ex) https://www.naver.com:8080/clientId=300
이때, 예비 요청을 안보내고 사용자의 요청을 바로 보낸다고 CORS 정책을 무시하는 게 아닙니다. 다만 정책과 상관 없이 요청을 보내도 괜찮다고 판단해 바로 요청하는 것 입니다. 만약 서버에서 GET 요청에 대한 CORS 정책을 설정하지 않았다면, 응답을 확인하고 브라우저가 사용자에게 GET 요청은 허용되지 않았다고 에러를 발생합니다.
2️⃣ Pre-flight Request(예비 요청)
사용자의 요청이 브라우저가 생각 했을 때, 안전한 요청이 아닐 수도 있다(=정책을 위배할 수도 있다)는 판단이 들면
사용자의 요청을 보내기 전에 "어떤 정책을 가졌니?" 라는 예비 요청을 보내게 됩니다(이때 요청은 Option Method를 사용). 타국으로 출국 전 우려되거나 위반되는 사항이 없는지 비자를 신청하는 과정과 비슷합니다.
즉, 단순 요청이 아닌 경우 브라우저는 먼저 예비 요청을 보내고, 응답으로 받은 CORS 정책을 확인합니다. 이 정책이 요청 조건에 부합하면 실제 요청을 전송하며, 부합하지 않을 경우 CORS 에러가 발생하게 됩니다.
브라우저가 먼저 예비 요청을 보내고, 응답온 CORS 정책을 확인. 위배되는 경우 에러를 발생 3️⃣ Credential Request(인증 요청)
마지막 요청으로는 인증 요청이 있습니다. 여기서 말하는 인증이란 토근과 같은 정보를 의미하며 이러한 정보는 민감한 정보이므로 함부로 요청에 넣을 수 없습니다. 인증 요청인 경우에는 양측 출처에서 모두 정책을 설정해줘야 주고 받을 수 있습니다.
- 프론트 출처 : Header에 withCredentials를 true로 설정해줍니다.
- 서버 출처 : Access-Control-Allow-Credentials를 true로 설정해줍니다.
이때 주의할 점으로 서버에서 Access-Control-Allow-Origin(어떤 출처를 허용할 것인가?)를 *(전체 허용)으로만 설정해두면 오류가 발생합니다. 민감 정보를 담는 요청을 허용하는 경우에는 꼭 어떤 출처에 대해서 허용할 것인지도 명시해줘야 합니다.
✍ CORS 테스트
CORS를 테스트 하기 위해서 별도의 local 환경을 오픈하는 것은 상당히 번거롭습니다. Postman(포스트맨)을 사용하면 Browser로 동작하지 않기에 Single Origin으로 인식합니다(Header에 Origin을 변경하여도, Browser의 역할을 담당하지는 않습니다). 이에 CORS를 테스트 하기 위한 2가지 방법을 추천 드립니다.
1. CORS Tester
https://cors-test.codehappy.dev/
CORS Tester - Test a URL for valid CORS headers
Use this little website to test if a URL is setup correctly to work with CORS. What is CORS? For security, browsers stop scripts from accessing URLs on different domains. This is done via CORS or Cross-Origin Resource Sharing. It is implemented by looking
cors-test.codehappy.dev
위 사이트에서 API 요청을 보낼 URL, 어느 출처에서 보낼 것인지에 대한 Origin, Method를 입력 후 Test를 진행하면 결과 값을 받을 수 있습니다.
2. CURL(with. window cmd)
window + r > cmd로 이동해 줍니다(curl은 window에 기본적으로 설치되어 있어 바로 진행하겠습니다).
curl -v -X OPTIONS "http://localhost:8080/assertion?userId=test" ^ -H "Origin: http://localhost:3000" ^ -H "Access-Control-Request-Method: GET" ^ -H "Access-Control-Request-Headers: Authorization"
위와 같이 요청을 보낼 API URL과 Header에 넣을 정보를 담아 엔터를 누르면 Response가 나오게됩니다.
'IT' 카테고리의 다른 글
☝️싱글톤(Singleton) 패턴 (0) 2025.06.24 - Method