Computer Engineering/Django

Django CORS 관련 설정하기 / django-cors-headers

jordan.bae 2023. 10. 29. 22:28

웹 개발을 하다보면 CORS(Cross-Origin Resource Sharing)와 같은 보안 이슈들이 흔히 발생합니다. 이는 브라우저가 서로 다른 호스트(도메인) 간의 자원 공유를 제한함으로써, 웹 애플리케이션의 보안을 강화하는 중요한 기능입니다. 이러한 제한의 근본적인 이유는 보안 취약점을 방지하기 위함인데, 예를 들어, CSRF(Cross-Site Request Forgery)와 같은 공격에서는 악의적인 웹사이트가 사용자의 브라우저에 저장된 인증 정보를 이용하여 다른 사이트에 요청을 보내는 행위를 막기 위함입니다.

 

데이터 엔지니어로 전향한 후에 오랜만에 서버 개발을 하려고 했더니 개념이 정확히 기억도 안 나고 사실 오랜만에 세션으로 인증을 구현할 일이 있어서 조금 헤맸습니다. CORS, CSRF, 쿠기, 인증등… 오랜만에 보니 머리아파서 넘겼던 부분들을 정리해보려고 합니다.

 

CORS (Cross-Origin Resource Sharing)

CORS는 다른 출처(origin)의 웹 페이지가 해당 출처의 자원에 접근할 수 있도록 하는 메커니즘입니다. 기본적으로 웹 브라우저는 동일 출처 정책(Same-Origin Policy)을 따르기 때문에 다른 출처의 자원에 접근하는 것이 제한되게 하는데 이를 제한합니다. 하지만, 요즘은 대부분 Front와 Backend Application은 보통 다른 Host를 갖게 되기 때문에 HTTP 통신 시 서버에서 관련 Header의 값을 설정해야 합니다.

서버 측에서 HTTP 응답 헤더에 다음과 같은 내용을 포함시키면 CORS 문제를 해결할 수 있습니다.

Access-Control-Allow-Origin: 통신할 Front Host

모든 Host에서 요청을 허용하려면 아래와 처럼 HTTP 응답 헤어데 다음과 같은 내용을 포함시키면 모든 도메인에서 요청을 허용할 수 있습니다. → 하지만, 보안적으로 좋지 않기 때문에 추천 드리지 않습니다.

Access-Control-Allow-Origin: *

 

응답 헤더에 Access-Control-Allow-Origin 추가하기

1. 직접 Middleware를 추가해서 해당 Header를 추가하기 (추천하지 않음.)

직접 middleware class를 정의한 후 setting.py에 MIDDLEWARE에 추가해주는 방법 있습니다.

대략적으로 www.doosikbae.com이라는 도메인에서 요청을 허용하려면 아래처럼 응답 HEADER를 변경할 수 있습니다.

class SimpleCorsMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)

        if request.method == 'OPTIONS' and "HTTP_ACCESS_CONTROL_REQUEST_METHOD" in request.META:
            response = self.preflight_response(request)
            return response

        response["Access-Control-Allow-Origin"] = "https://www.doosikbae.com"
        return response

    def preflight_response(self, request):
        response = HttpResponse()
        response["Access-Control-Allow-Origin"] = "https://www.doosikbae.com"
        response["Access-Control-Allow-Methods"] = "GET,POST,OPTIONS"
        response["Access-Control-Allow-Headers"] = "content-type,accept"
        response["Access-Control-Max-Age"] = "1800"  # 30 minutes cached
        return response

# settings
MIDDLEWARE = [
    ...
    'middleware.SimpleCorsMiddleware',
    ...
]

 

2. django-cors-headers 이용하기 (추천)

Python의 가장 큰 장점인 풍부한 라이브러리 생태계를 활용하는 것이 보안 및 생산성 측면에서는 추천하는 방법입니다.

해당 라이브러리를 활용하는 방법은 공식 문서에 정말 잘 설명이 되어 있기 때문에 생략하겠습니다.

한 가지만 이야기해 보면 모든 도메인의 요청을 허용하지 말고 허용할 도메인을 설정하는 것을 추천드립니다.

CORS_ALLOW_ALL_ORIGINS = True # 추천 하지 않음.

CORS_ALLOWED_ORIGINS = [
    "https://blog.doosikbae.com", # 추천
]

 

CORS 간단하게 브라우저 콘솔에서 테스트해 보기

fetch('test할 사이트')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

 

CORS 관련 설정 테스트를 google.com에서 콘솔에서 진행. (https://www.google.com을 CORS_ALLOWED_ORIGINS 에 넣었을 때와 안 넣었을 때 CORS Policy에 의해 막히는지 테스트)

 

 

다음에는 CSRF Token관련 글 k8s에 Django를 배포하면서 겪었던 어려움등에 대해서 포스팅 해보겠습니다.

 

관련  글 추천

- Django DB Transaction

 

Django DB Transaction 1편 - Request와 DB Transaction 묶기(Feat. ATOMIC_REQUESTS)

Introduction - Django DB Transaction 안녕하세요. 새해에는 Django와 관련된 글들을 많이 다뤄 보려고 합니다. 첫 번째로 Django에서 DB Transaction을 다루는 방법에 대해서 공부하고 글을 써보려고 합니다. 총

blog.doosikbae.com

- Django에서 CSRF공격을 막기

 

Django에서 CSRF 공격을 막기 및 CSRF 토큰의 이해와 활용

웹 보안에 있어서 중요한 공격 유형 중 하나인 CSRF(Cross-Site Request Forgery)는 사용자의 의도와 무관하게 공격자가 준비한 악의적인 요청을 보내게 만드는 기법입니다. 사용자가 로그인 상태에서 공

blog.doosikbae.com

반응형