브라우저의 동일 출처 정책 문제 해결 방법

현대 웹 애플리케이션에서 프론트엔드와 백엔드가 별도의 도메인으로 운영되는 경우, 클라이언트가 다른 도메인으로 요청을 보낼 때 브라우저는 기본적으로 보안상의 이유로 요청을 차단합니다. 이 현상을 '크로스 오리진 문제'라고 하며, 이를 해결하기 위해 CORS (Cross-Origin Resource Sharing) 표준이 도입되었습니다.

CORS는 브라우저와 서버 모두가 지원해야 하는 기술이며, 대부분의 현대 브라우저(IE10 이상)에서는 자동으로 처리됩니다. 개발자 입장에서는 일반적인 AJAX 요청과 동일한 코드로 작성할 수 있으며, 브라우저가 자동으로 추가 헤더를 삽입하거나 사전 검사를 수행합니다.

요청 유형 구분

  • 간단 요청 (Simple Request): GET, POST, HEAD 중 하나이며, 헤더에 다음 제한된 항목만 포함 가능.
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type: application/x-www-form-urlencoded, multipart/form-data, text/plain 만 허용
    → 단순 요청은 응답에 Access-Control-Allow-Origin 헤더만 포함하면 됩니다.
  • 복잡 요청 (Complex Request): 위 조건을 벗어나는 모든 요청입니다. 브라우저는 먼저 OPTIONS 요청을 보내 사전 검증을 수행하며, 이 과정을 preflight라 합니다.

기본 해결 방식: 응답 헤더 설정

서버 응답에 다음 헤더를 포함하면 크로스 오리진 요청을 허용할 수 있습니다:
{
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Headers": "Content-Type, Authorization",
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS"
}
> 주의: *는 모든 도메인을 허용하지만, 인증 정보가 필요한 경우 사용 불가. 실제 서비스에서는 특정 도메인만 허용하는 것이 안전합니다.

Django 프로젝트에서의 구현

Django 프로젝트에서는 django-cors-headers 패키지를 활용해 간편하게 설정할 수 있습니다.
  1. 설치:
    pip install django-cors-headers
  2. 설정 파일에 등록:
    # settings.py
    INSTALLED_APPS = [
        # ...
        'corsheaders',
        # ...
    ]
    
    MIDDLEWARE = [
        # ...
        'corsheaders.middleware.CorsMiddleware',
        'django.middleware.common.CommonMiddleware',
        # ...
    ]
  3. 보안 설정:
    CORS_ORIGIN_ALLOW_ALL = False  # 모든 도메인 허용 금지
    
    CORS_ORIGIN_WHITELIST = [
        'http://localhost:3000',
        'https://myapp.com'
    ]
    
    CORS_ALLOWED_METHODS = [
        'GET',
        'POST',
        'PUT',
        'PATCH',
        'DELETE',
        'OPTIONS'
    ]
    
    CORS_ALLOWED_HEADERS = [
        'Content-Type',
        'Authorization',
        'X-Requested-With',
        'X-CSRFToken',
        'token'
    ]
이 설정을 통해 프론트엔드와 백엔드가 다른 도메인에서도 안전하게 통신할 수 있습니다.

태그: Django CORS JavaScript web-security http-header

6월 19일 17:01에 게시됨