CORS(Cross-Origin Resource Sharing)는 웹 개발의 중요한 부분으로, 다양한 도메인 간에 자원을 공유할 수 있는 안전한 방법을 제공합니다. CORS의 구현은 서버가 특정 출처에서 오는 요청을 허용하도록 설정하는 HTTP 헤더를 포함시키는 방법으로 이루어집니다. 이런 설정은 웹 개발자와 서버 관리자가 협력하여 구현해야 할 필수적인 부분입니다. 웹 개발에 있어 CORS는 단순히 기술적인 요소를 넘어서, 보안, 접근성, 그리고 법적 책임을 모두 아우르는 중요한 개념입니다. 개발자는 CORS를 이해하고 올바르게 구현하여, 사용자와 클라이언트에게 안전하고 효과적인 웹 경험을 제공해야 합니다.
이 글에서는 CORS가 무엇인지, 왜 중요한지, 그리고 이를 이해해야 하는 이유를 설명하겠습니다.
CORS 란 무엇인가?
CORS(Cross-Origin Resource Sharing)는 웹 페이지에서 실행되는 스크립트가 다른 출처의 자원에 접근할 수 있도록 허용하는 보안 메커니즘입니다. 이는 웹 보안의 핵심 원칙인 같은 출처 정책(Same-Origin Policy)을 보완합니다. 같은 출처 정책은 웹 브라우저가 동일 출처(같은 프로토콜, 호스트, 포트를 사용)에서만 리소스를 불러오도록 제한하는 보안 정책입니다. CORS는 이 정책의 엄격함을 완화하여, 안전한 방식으로 출처가 다른 리소스와의 상호작용을 가능하게 합니다.
예를 들어, https://example.com에서 서비스되는 웹 페이지가 https://api.example.com에서 데이터를 가져오려 할 때, 두 URL의 도메인이 다르기 때문에 기본적으로는 이러한 요청이 불가능합니다. CORS는 이런 제한을 안전하게 우회할 수 있는 방법을 제공합니다.
CORS 작동 방식
CORS는 HTTP 헤더를 사용하여 브라우저와 서버 간에 출처 간 리소스 공유 규칙을 협상합니다. 기본적으로, 웹 애플리케이션이 다른 도메인의 리소스에 접근하려고 할 때, 브라우저는 서버에 사전 요청(pre-flight request)을 보냅니다. 이 사전 요청은 OPTIONS 메소드를 사용하여 서버에게 추가 정보 없이 리소스에 접근할 수 있는지를 묻는 것입니다.
이 요청에 대한 서버의 응답에는 다음과 같은 CORS 관련 헤더가 포함될 수 있습니다:
• Access-Control-Allow-Origin: 이 헤더는 해당 리소스에 접근할 수 있는 출처를 명시합니다. 특정 도메인을 명시하거나 모든 도메인을 의미하는 * (와일드카드)를 사용할 수 있습니다.
• Access-Control-Allow-Methods: 서버가 허용하는 HTTP 메소드(예: GET, POST 등)를 명시합니다.
• Access-Control-Allow-Headers: 서버가 허용하는 헤더를 명시합니다.
• Access-Control-Allow-Credentials: 쿠키나 HTTP 인증 정보 등 을 사용한 요청을 허용할지 여부를 명시합니다. 이 헤더가 true로 설정된 경우, Access-Control-Allow-Origin 헤더에는 *를 사용할 수 없습니다.
PlantUML 코드
@startuml participant Browser participant "Server (api.example.com)" == Simple Request == Browser -> "Server (api.example.com)": GET /resource note right: Request from origin\nexample.com "Server (api.example.com)" -> Browser: HTTP 200 OK\nAccess-Control-Allow-Origin: example.com == Preflight Request == Browser -> "Server (api.example.com)": OPTIONS /resource note right: Preflight request for POST method "Server (api.example.com)" -> Browser: HTTP 200 OK\nAccess-Control-Allow-Origin: example.com\nAccess-Control-Allow-Methods: POST, GET Browser -> "Server (api.example.com)": POST /resource "Server (api.example.com)" -> Browser: HTTP 200 OK\nAccess-Control-Allow-Origin: example.com @enduml |
1. 단순 요청 (Simple Request):
• 브라우저가 GET 요청을 보냅니다. 이는 일반적인 HTML, CSS, 이미지 파일 등의 간단한 리소스 요청에 해당합니다.
• 서버는 Access-Control-Allow-Origin 헤더를 포함하여 응답합니다. 이 헤더는 요청을 보낸 출처(example.com)가 서버의 리소스에 접근할 수 있음을 명시합니다.
2. 프리플라이트 요청 (Preflight Request):
• POST와 같이 특별한 메소드, 헤더, 또는 withCredentials가 true로 설정된 요청은 브라우저에 의해 사전에 검사 됩니다.
• 브라우저는 OPTIONS 메소드를 사용하여 서버에 사전 요청을 보냅니다. 이는 서버에게 실제 요청을 보내도 안전한지 확인하는 과정입니다.
• 서버는 허용하는 메소드와 출처를 포함하여 응답합니다.
• 사전 요청이 성공하면, 브라우저는 실제 POST 요청을 보냅니다.
CORS가 중요한 이유
1. 보안 유지: CORS는 악의적인 사이트가 사용자 데이터를 훔치거나 불법적인 행위를 수행하는 것을 방지하면서도, 필요할 때 안전하게 자원을 공유할 수 있도록 합니다.
2. API 활용성 증가: 많은 웹 서비스가 API를 통해 데이터를 제공합니다. CORS를 이해하고 구현하면, 다양한 출처에서 자신의 서비스에 접근하도록 허용할 수 있습니다.
3. 개발 편의성: 개발 중에 자주 발생할 수 있는 다양한 출처의 리소스를 통합하는 문제를 해결할 수 있습니다.
CORS를 이해해야 하는 이유
• 개발 효율성: CORS를 이해하면, 웹 애플리케이션을 더 빠르고 효율적으로 개발할 수 있습니다. 문제를 신속하게 진단하고 해결할 수 있는 능력은 프로젝트 시간을 단축시키고, 고객 만족도를 높일 수 있습니다.
• 규제 준수: 많은 국가와 산업에서 데이터 보호 및 개인 정보 보호 규정을 엄격히 적용하고 있습니다. CORS는 이러한 법적 요구사항을 준수하는 데 중요한 역할을 할 수 있습니다.
• 시스템 통합: 대규모 시스템을 개발하거나 여러 시스템을 통합할 때 CORS를 이해하면, 다양한 시스템 간의 상호작용을 더 잘 관리할 수 있습니다.
CORS 이슈 사례 정리
CORS(Cross-Origin Resource Sharing) 이슈는 웹 개발 중 흔히 마주치는 문제 중 하나입니다. 이러한 이슈들은 다양한 상황에서 발생할 수 있으며, 그에 따른 해결책도 다양합니다. 아래에서는 몇 가지 일반적인 CORS 이슈 사례와 그 해소 방안을 정리해 보겠습니다.
사례 1: API 요청 거부
상황: 프론트엔드 코드가 https://example.com에서 호스팅 되고 있으며, https://api.example.com에서 제공하는 API에 요청을 보내고 있습니다. 이때 브라우저가 요청을 차단합니다.
해소 방안:
1. 서버 설정 변경: API 서버의 응답 헤더에 Access-Control-Allow-Origin: https://example.com를 추가하여 명시적으로 요청을 허용합니다.
2. 프락시 서버 사용: 개발 중에는 프론트엔드 서버를 프락시로 설정하여 API 요청을 중계할 수 있습니다. 예를 들어, 개발 서버의 설정에서 /api 경로를 https://api.example.com으로 리디렉션 하는 방법이 있습니다.
사례 2: 자격 증명이 포함된 요청
상황: 사용자 인증 정보(Cookies, Authentication headers 등)를 포함하여 크로스-도메인 API 요청을 보내려고 할 때 차단됨.
해소 방안:
1. 헤더 설정 추가: 서버의 응답 헤더에 Access-Control-Allow-Credentials: true와 함께 Access-Control-Allow-Origin을 명시적으로 설정해야 합니다. 여기서 주의할 점은 Access-Control-Allow-Origin에 와일드카드(*)를 사용할 수 없다는 것입니다.
2. 클라이언트 설정 조정: XMLHttpRequest 또는 Fetch API를 사용하는 클라이언트 코드에서 withCredentials 속성을 true로 설정해야 합니다.
사례 3: 다양한 HTTP 메소드 사용
상황: POST, PUT, DELETE와 같은 다양한 HTTP 메소드를 사용하는 요청을 보낼 때 특정 메소드가 차단됨.
해소 방안:
1. 프리플라이트 요청 대응: 서버에서는 CORS 프리플라이트 요청을 처리할 수 있어야 합니다. 이를 위해 OPTIONS 요청에 대한 응답으로 Access-Control-Allow-Methods에 필요한 HTTP 메소드들을 포함시켜야 합니다.
사례 4: 제한된 헤더 사용
상황: 사용자 정의 헤더를 요청에 포함시킬 때 브라우저가 요청을 차단합니다.
해소 방안:
1. 허용 헤더 명시: 서버의 응답 헤더에 Access-Control-Allow-Headers를 설정하여 요청에서 사용된 헤더들을 명시적으로 허용해야 합니다.
댓글