[Django] 장고 CORS 크로스 도메인 이슈

Django로 API 서버를 만드는데 cors에러가 떴다 ... Cross Domain 이슈가 발생한건데, 이 문제는 왜 발생하는 걸까 ?

CORS

CORS는 Cross Origin Resource Sharing의 약자로

도메인 또는 포트가 다른 서버의 자원을 요청하는 매커니즘이다.

 

최근 대부분의 웹 브라우저는 Javascript를 이용한 AJAX(Asynchronous Javascript XML)통신을 통한 데이터 송수신을 하는데,

다른 도메인을 가진 서버의 URL을 호출해 데이터를 가져오려고 하는 경우

보안 문제인 Cross Domain 이슈를 발생시킨다.


왜냐하면 만약 우리 웹 서비스에서 사용하기 위해 다른 서브 도메인을 가진 API 서버를 구축했는데, 우리가 아닌 다른 웹 서비스에서 이 API 버서에 접근해서 마음대로 API를 호출해서 사용하면 안되기 때문이다.

 

예를들어, www.ozit.co.kr 도메인에선 www.ozit.co.kr 도메인 내에 있는 URL 만을 호출할 수 있다.
www.ozit.co.kr 도메인에서 www.tistory.com도메인의 URL은 AJAX로 호출할 수가 없다.

 

 

Javascript는 동일 출처 정책이라는 정책을 두어 도메인이 다른 서버로부터 요청을 받으면 보안 문제로 간주하고 CORS 이슈를 발생시켜 이를 차단한다.

 

동일 출처 정책(Same Origin Policy) 때문에 CORS가 발생하는데, 브라우저에서 외부 서버가 cross-origin HTTP로 요청한 데이터를 보안 목적으로 차단한다. 그래서 데이터를 받을 수가 없다.

즉, 자신과 동일한 도메인에 한해서만 요청을 허용하고 처리해준다.

 

CORS 문제 해결 방법

CORS 문제는 다른 도메인의 서버로부터 요청이 들어왔을 때, 헤더에 접근을 허락하는 내용이 없으면 발생한다.

예를 들어 클라이언트는 localhost:3000이고 외부 서버는 localhost:8000이면 포트가 달라서 CORS가 발생할 수 있다.

 

(가장 쉬운 해결방법은 클라이언트와 서버가 같은 도메인과 포트를 사용하는 거지만.. )


이럴 경우 외부 서버에서 보내는 요청의 헤더(Access-Control-Allow-Origin response 헤더)에 cross origin HTTP 요청을 허가해 접근을 허락하는 내용을 추가해 주면 된다.

 

cross origin HTTP 요청을 허가해주는 방법

헤더에 접근을 허락하는 내용을 추가

1. pip install로 django-cors-headers 앱을 설치한다.

django-cors-headers는 Cross-Origin Resource Sharing(CORS) 에 필요한 서버의 헤더를 조작하기 위한 Django 앱이다.

$ pip install django-cors-headers

django-cors-headers  장고앱을 이용해서 response에 CORS(Cross Origin Resource Sharing) 헤더를 추가한다,

이렇게 하면 다른 서버에서로부터 내 서버 앱으로 들어오는 브라우저를 통한 요청을 허가한다.

 

2. installed apps 목록에 corsheaders를 추가한다.

INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
]

 

3. middleware class도 추가해야 한다.

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware', # <- 가능한 높게 위치시켜야 한다.
    'django.middleware.common.CommonMiddleware', 
    ...
]

CorsMiddleware는 가능한 높게 위치시켜야 한다.

특히 Django의 CommonMiddleware나 Whitenoise의 WhiteNoiseMiddleware와 같은 응답을 생성할 수 있는 미들웨어 전이어야 한다.

이러한 미들웨어 전이 아닌 경우엔, 이러한 응답들에 CORS 헤더를 추가할 수 없기 때문이다.

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

 

4. Django settings에서 미들웨어의 동작을 구성해야 한다.

CORS_ORIGIN_WHITELIST에는 cross-site 요청을 허용하는 호스트들을 추가한다.

또는 모든 호스트를 허용하고 싶으면 CORS_ORIGIN_ALLOW_ALL을 True로 설정한다. 만약 CORS_ORIGIN_ALLOW_ALL이 True 이면, whitelist는 쓰이지 않고, 모든 origin에서의 요청이 허용된다.

Default는 False이다.

 

CORS_ORIGIN_WHITELIST는 cross-site HTTP 요청을 할 수 있는 권한이 주어지는 origin들의 리스트이다.

Default는 [] 이다.

 

Origin은 URI scheme + hostname + port 등으로 정의된다.

CORS_ORIGIN_ALLOW_ALL = True # <- 모든 호스트 허용

# or 

CORS_ORIGIN_WHITELIST = (
    "https://example.com",
    "https://sub.example.com",
    "http://localhost:8080",
    "http://127.0.0.1:9000"
)

이렇게 헤더에 추가해주면 된다.

 

5. 5번부터는 쓰지 않아도 되는 선택적인 세팅이다. 몇 가지만 살펴보겠다.

 

CORS_ALLOW_CREDENTIALS

CORS_ALLOW_CREDENTIALS가 True인 경우, 쿠키가 cross-site HTTP 요청에 포함될 수 있다. 기본값은 False이다.

CORS_ALLOW_CREDENTIALS = True

 

CORS_ALLOW_METHODS

실제 요청에 허용되는 HTTP 동사 리스트이다. 기본값은 다음과 같다:

CORS_ALLOW_METHODS = [
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
]

기본값은 corsheaders.defaults.default_methods로 임포트 할 수 있으므로, 커스텀 메소드들은 확장해서 사용하면 된다.

예를 들어:

from corsheaders.defaults import default_methods

CORS_ALLOW_METHODS = list(default_methods) + [
    'POKE',
]

 

CORS_ALLOW_HEADERS

실제 요청을 할 때 사용될 수 있는 non-standard HTTP 헤더 목록이다. 기본값을 다음과 같다:

CORS_ALLOW_HEADERS = [
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
]

이것 또한 기본값은 corsheaders.defaults.default_headers로 임포트 할 수 있으므로, custom 헤더들은 확장해서 사용하면 된다.

예를 들어:

from corsheaders.defaults import default_headers

CORS_ALLOW_HEADERS = list(default_headers) + [
	'my-custom-header'
]

 

SETTINGS.PY

위의 내용을 바탕으로 작성한 settings.py 파일의 일부이다.

INSTALLED_APPS = [
	'corsheaders',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'account',
    'product',
    'review',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'corsheaders.middleware.CorsMiddleware',
]

CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True

CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
)

CORS_ALLOW_HEADERS = (
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
)

 


* URL과 도메인의 차이

1) URL
URL은 도메인을 포함하는 경로이다. 특정 웹사이트의 특정 위치까지 가기위한 전체 경로라고 보면 된다
출처: https://na27.tistory.com/149 [na27]
예를 들어 TEST 폴더 안의 TEST.PDF라는 파일은 http://도메인/test/test.pdf/ 가 URL이다.

 

2) 도메인
도메인은 예를 들어 http://www.naver.com 에서 www.naver.com이 도메인이다.

  • DNS(Domain Name System) 서버
    사용자가 웹사이트에 접속할 때 도메인 이름(www.naver.com)접속하면, DNS 서버에 도메인 이름이 보내진다. 그럼 DNS 서버는 그 도메인 이름에 연결된 아이피 주소(ex. 202.179.177.22 2017년 9월 17일 기준 네이버 웹사이트 IP 주소) 응답을 사용자 컴퓨터에 보낸다. 그럼 사용자는 응답받은 아이피 주소로 실제 데이터 처리를 하는 서버에 다시 데이터 요청을 하고 데이터를 응답 받게 된다.

Reference

https://pypi.org/project/django-cors-headers/

CORS 크로스 도메인 이슈 (No 'Access-Control-Allow-Origin' header is present on the requested resource)
URL가 도메인의 차이가 뭔가요?
Domain과 URL 이해
CORS 문제 해결 방법
CORS에 대한 간단한 고찰
Django, Js 교차 CORS 오류에 대한 대책

[출처] https://oen-blog.tistory.com/46

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
87 [python 일반] 파이썬에서 도커 사용하기: 기초부터 배포까지 졸리운_곰 2024.12.01 410
86 [python 일반] 파이썬 디컴파일 방지 난독화 초간단 방법 file 졸리운_곰 2024.08.13 539
85 [python 일반] [Python] python 예제 - 프로그램 실행 위치 확인 방법 3종 - os.getcwd,... 졸리운_곰 2024.07.28 451
84 [python 일반] [Python] How to capture output of Python's interpreter and show in a Text widget? 졸리운_곰 2024.07.26 230
83 [python 일반] [Python] How to Fix Python’s “List Index Out of Range” Error in For Loops 졸리운_곰 2024.07.26 284
82 [python 일반] [Python] Python 리스트에 특정 값이 있는지 체크하기 졸리운_곰 2024.07.26 418
81 [python 일반] [Python] 원하는 시간마다 파이썬 자동 실행 file 졸리운_곰 2024.07.25 337
80 [python 일반] [Python] pyinstaller] PyInstaller -i, --add-data로 아이콘(icon)을 포함하자 file 졸리운_곰 2024.07.19 428
79 [python 일반] [Python] pyinstaller : 파이썬 컴파일 시 코드 암호화 & 복호화 file 졸리운_곰 2024.06.10 374
78 [python 일반] ** Date형식을 String형식으로 변환 ** 졸리운_곰 2024.06.08 297
77 [python 일반] [Python] strftime과 strptime file 졸리운_곰 2024.06.07 377
76 [python 일반] How to Run a Periodic Background Task in Python 졸리운_곰 2024.06.07 324
75 [python 일반] *win32ctypes.pywin32.pywintypes.error when using pyinstaller in VS Code - Possible Virus/Trojan? 졸리운_곰 2024.06.07 453
74 [python 일반] 【Python】The 'pathlib' package is an obsolete backport of a standard library ・・・ 졸리운_곰 2024.05.30 318
73 [Python 일반] 파이썬 exe 파일 만들기 졸리운_곰 2024.05.30 307
72 [Python] 클립보드 무엇인가? Pyperclip을 통한 자동화 file 졸리운_곰 2024.05.06 364
71 [Python] PyQt와 PySide에 대한 잡설 file 졸리운_곰 2024.04.25 253
70 [python 일반] How to Update All Python Packages : 설치된 파이썬 패키지 모두 업데이트 하기 file 졸리운_곰 2024.03.16 604
69 [python, C++] Interfacing C++ and Python with the Python API : C++ 및 Python과 Python API의 인터페이스 file 졸리운_곰 2023.08.18 302
68 [python 일반] 파이참 에러 : Fatal Python error: init_stdio_encoding: failed to get the Python codec name of the stdio encoding file 졸리운_곰 2023.07.06 354
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED