All that I've dreamed of

Django React 백엔드 - 클라이언트 쿠키공유 (서브도메인, Cors헤더, csrf설정) 본문

Django

Django React 백엔드 - 클라이언트 쿠키공유 (서브도메인, Cors헤더, csrf설정)

_베토디 2023. 1. 5. 17:14
반응형

* 여기저기 알아보고 이것저것 시도해보고 정리한 내용이니 정답이 아님을 주의~!

 

사전 세팅

 

📌 백엔드: Django -> EC2 + Nginx + gunicorn 배포완료 + 도메인 설정 (예시) https://내프로젝트.com

📌 프론트엔드: React -> S3정적웹호스팅 + Cloudfront 배포완료 + 서브도메인 설정 (예시) https://www.내프로젝트.com

 

SOP 와 CORS 그리고 Samesite

 

브라우저는 SOP (동일출처정책)을 따른다.

동일 출처란 Same-Origin. 즉, 프로토콜+도메인+포트 까지 일치해야 함을 의미한다.

예) https://abcd.com:8000 서버에는 https://abcd.com:8000 의 출처만 api 요청을 허용 

위 정책을 위반하게 되면 만나게 되는 에러가 CORS 에러이고

Cross-origin 교차출처의 요청을 따로 지정해서 허용해 주면 CORS 정책에 위반되지 않게 된다.

 

Cross-origin로 부터의 리소스를 허용

클라이언트의 요청헤더에  Origin을 명시해 주고, 서버의 응답헤더의 Access-control-allow-origin 을 설정한다.

브라우저는 자신이 보낸 origin와 응답받은 origin을 비교해서 이 둘이 일치하게 되면

동일 출처가 아닌데도 서버에서 허용했으니 리소스를 받아도 되겠구나라고 판단하게 된다.

cors 정책을 지키기 위해서는 서버에서 api 요청을 보내오는 곳의 접근을 허용한다고 설정해 주고 클라이언트에 응답해 주어야한다.

 

클라이언트 / 백엔드 서버에서의 설정

 

🙋‍♀️ 클라이언트 (React)

* axios를 사용하는 경우

const instance = axios.create({
    URL: "https://project.com/api/v1/",
    withCredentials: true, 
})

🙋‍♀️ 백엔드 (Django )

👉 django-cors-headers 가 이미 설치/설정 되어있다는 가정 하에...

 

✔️참조 django-cors-headers 설치 및 세팅

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

# settings.py

CORS_ALLOWED_ORIGINS = ["https://www.내프로젝트.com"]

CORS_ALLOW_CREDENTIALS = True

CSRF_TRUSTED_ORIGINS = ["https://www.내프로젝트.com"]

CORS_ALLOWED_ORIGINS = ["https://www.project.com"]

=> 응답헤더에 Access-Control-Allow-Origin: https://www.내프로젝트.com로 표시된다

CORS_ALLOW_CREDENTIALS = True

=> 응답헤더에 Access-Control-Allow-Credentials: true 로 표시된다

CSRF_TRUSTED_ORIGINS = ["https://www.내프로젝트.com"]

=> 이곳에 명시된 곳으로 부터의 post 요청등을 허용한다, 이 설정을 하지 않으면 csrf failed 오류가 발생

 

 

✔️ 참고

CORS_ORIGIN_WHITELIST = [] 는 CORS_ALLOWED_ORIGINS의 예전 버전(?) 이라고 한다.

물론 지금도 사용해도 되지만 두 개를 같이 쓸 경우 CORS_ALLOWED_ORIGINS이 우선한다고 한다.

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

 

 

서브도메인 간 쿠키 공유

위의 설정들을 마쳐도 클라이언트 애플리케이션에 공유되는 쿠키가 없다면 다음 설정을 해보자..

 

# settings.py

SESSION_COOKIE_DOMAIN = "내프로젝트.com"
CSRF_COOKIE_DOMAIN = "내프로젝트.com"

위의 설정은 서브 크로스 도메인 간 요청을 허락해 준다

 

✔️ 참고: SESSION_COOKIE_DOMAIN, CSRF_COOKIE_DOMAIN

https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-SESSION_COOKIE_DOMAIN

https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-CSRF_COOKIE_DOMAIN

 

SESSION_COOKIE_DOMAIN
Default: None
The domain to use for session cookies. Set this to a string such as "example.com" for cross-domain cookies, or use None for a standard domain cookie.
To use cross-domain cookies with CSRF_USE_SESSIONS, you must include a leading dot (e.g. ".example.com") to accommodate the CSRF middleware’s referer checking.

(아래 번역은 내가 한거라 틀릴 수도 있음...주의)

세션 쿠키를 사용하려는 도메인
크로스 도메인간에 쿠키를 사용하고 싶으면 "example.com" 과 같이 문자열로 지정해주면 된다.
None (디폴트값)으로 하게 되면 기존 도메인(서버측 말하는 건가..?)에서만 사용할 수 있다.

CSRF_USE_SESSIONS로 크로스 도메인 쿠기를 사용하려면,
".example.com"과 같이 도메인 앞에 도트를 넣어야 한다. 

궁금하니까 찾아봅시다

CSRF_USE_SESSIONS
Default: False
Whether to store the CSRF token in the user’s session instead of in a cookie. It requires the use of django.contrib.sessions.
Storing the CSRF token in a cookie (Django’s default) is safe, but storing it in the session is common practice in other web frameworks and therefore sometimes demanded by security auditors.
Since the default error views require the CSRF token, SessionMiddleware must appear in MIDDLEWARE before any middleware that may raise an exception to trigger an error view (such as PermissionDenied) if you’re using CSRF_USE_SESSIONS. See Middleware ordering.
=> 대강 요약하자면 이 설정을 사용하면 쿠키 안에 csrf token이 있더라도 django session 을 사용하게 된다
=> 이 설정을 사용하면 csrftoken의 이름이 sessionid 로 바뀌게 된다
=> 프론트엔드가 쿠키에서 csrftoken 값을 찾아서 백엔드로 보내줘야 하는데 이름을 바꾸자면 안되니까 이 설정은 사용x

CSRF_COOKIE_DOMAIN
Default: None
The domain to be used when setting the CSRF cookie. This can be useful for easily allowing cross-subdomain requests to be excluded from the normal cross site request forgery protection. It should be set to a string such as ".example.com" to allow a POST request from a form on one subdomain to be accepted by a view served from another subdomain.
Please note that the presence of this setting does not imply that Django’s CSRF protection is safe from cross-subdomain attacks by default - please see the CSRF limitations section.

csrf 쿠키를 세팅할 사용되는 도메인. 서브 크로스 도메인간 요청이 크로스 사이트의 위조방지로부터 제외되도록 해준다. 문자열로 세팅되어야 하고 서브도메인의 POST 요청을 허용해준다. 

📌 최종 settings.py 설정

# settings.py

...

CORS_ALLOWED_ORIGINS = ["https://www.내프로젝트.com"]
CSRF_TRUSTED_ORIGINS = ["https://www.내프로젝트.com"]
CORS_ALLOW_CREDENTIALS = True

SESSION_COOKIE_DOMAIN = "내프로젝트.com"
CSRF_COOKIE_DOMAIN = "내프로젝트.com"

 

 

 

🍪서버측 쿠키

백엔드가 실행되고 있는 브라우저에서 애플리케이션에 sessionid 와 csrftoken 이 잘 들어와 있다.

이전과 다른 것이 Domain 이 그냥 내프로젝트.com 이 아닌 .내프로젝트.com 으로 되어있다는 것.

도메인 앞에 . (도트)가 붙으면 해당 루트도메인의 모든 서브도메인을 포함한다는 것 같다.

그럼 프론트엔드 브라우저에도 쿠키가 제대로 들어와 있는지 확인해 보자... 두근두근

 

🍪클라이언트측 쿠키

www.내프로젝트.com  프론트엔드 브라우저에도 쿠키가 잘 들어와있다...!! 

로그아웃, 글 작성, 삭제 등 post 요청을 해보면 잘 된다!

 

 

 

Comments