* 상황

server console
front console1
front console2

원래 이런 문제가 없었는데, 갑자기 생긴 문제이다. POST로 server에 요청을 보내면 요청을 받지도 못하고 server에서 forbidden 처리해버린다.

 

 

* 원인

CSRF : 사이트 간 요청 위조(Cross-site request forgery)로, 웹사이트 취약점 공격 중 하나이다. 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위를 특정 웹사이트에 요청하게 하는 공격을 말한다.

Django는 이 CSRF 취약점을 막기 위해 CSRF 토큰방식을 기본으로 제공하는데, front에서 이 token없이 보내는 get이 아닌 모든 request는 forbidden 처리된다.

근데 일주일 전까지만 해도 괜찮았는데 갑자기 왜 그러지?

 

* 해결법

1. settings.py 변경

MIDDLEWARE = [
    # 'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    # 'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

csrf token 기능과 관련된 위 3개의 미들웨어를 주석처리하는 것이다. 근데 난 admin 기능이 필요해서 이 방법은 사용 안했다.

 

(2) front에서 token 꺼내서 전달.

 

쿠키에서 보면 csrftoken이 저장되어 있다. 이를 request 날릴 때, headers에 넣어주면 된다.

import { Cookies } from "react-cookie";

const CSRFToken = new Cookies();

const handleCreateButtonPressed = () => {
        var requestOptions = {
            method: "POST",
            headers: { "Content-Type": "application/json", "X-CSRFToken": CSRFToken.get('csrftoken')},
            body: JSON.stringify({
             ...
            }),
        };

        fetch("/accounts/login/", requestOptions)
            .then((response) => {
              ...
                }
            }
        );
    }

 

"X-CSRFToken": CSRFToken.get('csrftoken')

나는 react를 써서 위와 같은 방법으로 token을 꺼내왔다.

'Django' 카테고리의 다른 글

[DRF] request.user = AnonymousUser / request.auth = None  (0) 2022.07.25
* 상황

DRF로 회원가입, 로그인, 로그아웃을 구현했으나, headers 영역에 유저(token 또는 authorization) 정보가 저장되지 않아서, 인증기능이 제대로 작동하지 않는 현상이 발생했다.

 

request.user, request.auth, request.META, request.headers 어디에도 인증한 정보가 있지 않았다.

 

 

 

(1) 현재 나는 django.contrib.auth.models에서 기본으로 제공하는 AbstractUser 모델을 확장한 User 모델을 사용 중이다.

(2) 그래서 settings에 아래와 같이 명시를 해준 상태다.

 

(3) 원래 drf에서는 

위와 같이 DEFAULT_AUTHENTICATION_CLASSES를 통해, default로 사용할 인증 클래스를 명시해주어야 하고, 이를 기반으로 Token 생성 및 Token을 headers 부분에 authorization으로 적재하는 것도 이루어진다.

그런데 나처럼 Users 모델을 customizing한 경우, django.contrib.auth가 이 authentication를 도울 수 없어서 발생한 것이라 한다.

 

우선 급한 조치로 front에서 보낸 token이 유효한지 직접 확인하는 방식으로 했으나, 추후 이를 따로 token 확인 클래스로 빼든, 아니면 위 문제를 해결해보든 해야겠다.

class LogoutView(APIView):
    permission_classes = [AllowAny]
    def post(self, request):
        try:
            user = User.objects.filter(id=Token.objects.filter(key=request.data['token'])[0].user_id)[0]
        except:
            return Response(status=401)
        if user.is_authenticated:
            user.auth_token.delete()
            return Response(status=status.HTTP_200_OK)
        else:
            return Response(status=401)

'Django' 카테고리의 다른 글

Server ERROR : Forbidden_(CSRF Failed: CSRF token missing.)  (0) 2022.07.30

+ Recent posts