장고의 CSRF 보호를 사용하는 방법

당신의 뷰에서 CSRF 보호를 활용하려면 다음 단계를 따르십시오:

  1. CSRF 미들웨어는 MIDDLEWARE 설정에서 기본적으로 활성화되어 있습니다. 해당 설정을 덮어쓰는 경우에는, CSRF 공격이 처리되었다고 가정하는 모든 뷰 미들웨어 앞에 ``’django.middleware.csrf.CsrfViewMiddleware’``가 와야 함을 기억하십시오.

    사용하지 않도록 설정한 경우(권장하지 않음), 보호하려는 특정 뷰에서 :func:`~django.views.decorators.csrf.csrf_protect`를 사용할 수 있습니다(아래 참조).

  2. POST 양식을 사용하는 모든 템플릿에서, 양식이 내부 URL용인 경우 <form> 요소 내부에 csrf_token 태그를 사용하세요. 예:

    <form method="post">{% csrf_token %}
    

    외부 URL을 대상으로 하는 POST 양식에 대해서는 이렇게 할 수 없습니다. CSRF 토큰이 누출되어 취약점이 발생할 수 있기 때문입니다.

  3. 해당 뷰 함수에서 render 함수, 제네릭 뷰, 또는 contrib apps를 사용하는 경우, 이들은 모두 ``RequestContext``를 사용하므로 확인할 필요가 업습니다.

AJAX와 함께 CSRF 보호 사용

위의 방법을 AJAX POST 요청에 사용할 수 있지만 몇 가지 불편한 점이 있습니다: 모든 POST 요청에 POST 데이터로 CSRF 토큰을 전달해야 합니다. 이러한 불편함 때문에, 다른 대체 방법이 있습니다: 각 XMLHttpRequest에서 사용자 지정 X-CSRFToken 헤더(CSRF_HEADER_NAME 설정에 지정된 대로)를 CSRF 토큰 값으로 설정합니다. 많은 JavaScript 프레임워크가 모든 요청에 대해 헤더를 설정할 수 있도록 하는 후크를 제공하기 때문에 이 방식이 종종 더 쉽습니다.

먼저, CSRF 토큰을 받아야 합니다. 그 방법은 CSRF_USE_SESSIONSCSRF_COOKIE_HTTPONLY 설정이 활성화되어 있는지 여부에 따라 다릅니다.

AJAX 요청에 대한 토큰 설정

마지막으로, AJAX 요청에 헤더를 설정해야 합니다. fetch() API 사용:

const request = new Request(
    /* URL */,
    {
        method: 'POST',
        headers: {'X-CSRFToken': csrftoken},
        mode: 'same-origin' // Do not send CSRF token to another domain.
    }
);
fetch(request).then(function(response) {
    // ...
});

Jinja2 템플릿에서 CSRF 보호 사용

장고의 Jinja2 템플릿 백엔드는 장고의 템플릿 언어 내의 ``{% csrf_token %}``에 해당하는 모든 템플릿의 컨텍스트에 ``{{ csrf_input }}``를 추가합니다. 예를 들어:

<form method="post">{{ csrf_input }}

데코레이터 메서드 사용

``CsrfViewMiddleware``를 포괄적인 보호 기능으로 추가하는 대신 보호가 필요한 특정 뷰에 정확히 동일한 기능을 가진 csrf_protect() 데코레이터를 사용할 수 있습니다. 이는 출력에 CSRF 토큰을 삽입하는 뷰와 POST 양식 데이터를 수락하는 뷰에서 둘 다 사용해야 합니다. (이 둘은 종종 동일한 뷰 함수이지만, 항상 그런 것은 아닙니다).

데코레이터를 그 자체로 사용하는 것은 권장하지 않습니다. 사용하는 것을 잊어버리면 보안 구멍이 생기기 때문입니다. 둘 다 사용하는 ‘벨트 및 버팀대’ 전략은 괜찮으며, 이 경우 최소한의 오버헤드가 발생합니다.

거부된 요청 처리

기본적으로, 들어오는 요청이 ``CsrfViewMiddleware``에서 수행한 검사에 실패하면 ‘403 Forbidden’ 응답이 사용자에게 전송됩니다. 이것은 실제 Cross Site Request Forgery가 있거나, 프로그래밍 오류로 인해 CSRF 토큰이 POST 양식에 포함되지 않은 경우에만 전송되어야 합니다.

그러나 오류 페이지는 그다지 친숙하지 않으므로 이 조건을 처리하기 위한 고유한 뷰를 제공할 수 있습니다. 이렇게 하려면, :setting:`CSRF_FAILURE_VIEW`를 설정합니다.

CSRF 실패는 django.security.csrf 로거에 경고로 기록됩니다.

캐싱과 함께 CSRF 보호 사용

csrf_token 템플릿 태그가 템플릿에서 사용되는 경우(또는 get_token 함수가 다른 방식으로 호출되는 경우), CsrfViewMiddleware``는 쿠키와 ``Vary: Cookie 헤더를 응답에 추가합니다. 이것은 미들웨어가 지시된 대로 잘 사용된다면 캐시 미들웨어와 함께 잘 작동함을 의미합니다(``UpdateCacheMiddleware``는 다른 모든 미들웨어보다 먼저 실행됨).

그러나 개별 뷰에서 캐시 데코레이터를 사용하는 경우, CSRF 미들웨어는 아직 Vary 헤더 또는 CSRF 쿠키를 설정할 수 없으며 응답은 둘 중 하나만 캐시됩니다. 이 경우 CSRF 토큰을 삽입해야 하는 모든 뷰에서 django.views.decorators.csrf.csrf_protect() 데코레이터를 먼저 사용해야 합니다.

from django.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_protect


@cache_page(60 * 15)
@csrf_protect
def my_view(request): ...

클래스 기반 보기를 사용하는 경우, :ref:`클래스 기반 뷰 꾸미기<decorating-class-based-views>`를 참조할 수 있습니다.

테스트 및 CSRF 보호

CsrfViewMiddleware``는 일반적으로 모든 POST 요청과 함께 보내야 하는 CSRF 토큰이 필요하기 때문에, 기능을 테스트하는 방해가 됩니다. 이러한 이유로 장고의 테스트용 HTTP 클라이언트는 미들웨어와 ``csrf_protect 데코레이터를 완화하는 요청에 플래그를 설정하여 더 이상 요청을 거부하지 않도록 수정되어 있습니다. 다른 모든 측면(예: 쿠키 보내기 등)에서는 동일하게 동작합니다.

혹시, 테스트 클라이언트가 CSRF 확인을 실행하길 원한다면, CSRF 확인을 실행하는 객체를 생성할 수 있습니다.

>>> from django.test import Client
>>> csrf_client = Client(enforce_csrf_checks=True)

경계 조건들

특정 뷰에는 여기에서 예상하고 있는 일반적인 패턴에 맞지 않는 비정상적인 요구 사항이 있을 수 있습니다. 이러한 상황에는 여러 유틸리티를 사용할 수 있습니다. 필요할 수 있는 시나리오는 다음 섹션에 설명되어 있습니다.

일부 뷰에 대한 CSRF 보호 비활성화

대부분의 뷰에는 CSRF 보호가 필요하지만 일부는 그렇지 않습니다.

해결책: 미들웨어를 비활성화하고 필요한 모든 보기에 ``csrf_protect``를 적용하는 대신, 미들웨어를 활성화하고 :func:`~django.views.decorators.csrf.csrf_exempt`를 사용하세요.

``CsrfViewMiddleware.process_view()``를 사용하지 않을 때 토큰 설정

404 및 500 핸들러와 같이 뷰가 실행되기 전에 ``CsrfViewMiddleware.process_view``가 실행되지 않는 경우들이 있습니다. 하지만 여전히 양식에는 CSRF 토큰이 필요합니다.

해결책: :func:`~django.views.decorators.csrf.requires_csrf_token`을 사용하세요.

보호되지 않은 뷰에 CSRF 토큰 include하기

보호되지 않았거나 ``csrf_exempt``에 의해 면제되었지만, 여전히 CSRF 토큰을 포함해야 하는 일부 뷰가 있을 수 있습니다.

해결책: csrf_exempt() 다음에 :func:`~django.views.decorators.csrf.requires_csrf_token`을 사용하세요. (즉, ``requires_csrf_token``은 가장 안쪽 데코레이터여야 함).

하나의 경로에 대해서만 뷰 보호

한 가지 조건 세트에서만 CSRF 보호를 필요로 하며, 나머지 시간 동안에는 보호하지 않아야 하는 뷰.

솔루션: 전체 뷰 기능에는 :func:`~django.views.decorators.csrf.csrf_exempt`를 사용하고 보호가 필요한 경로에는 :func:`~django.views.decorators.csrf.csrf_protect`를 사용합니다. 예시:

from django.views.decorators.csrf import csrf_exempt, csrf_protect


@csrf_exempt
def my_view(request):
    @csrf_protect
    def protected_path(request):
        do_something()

    if some_condition():
        return protected_path(request)
    else:
        do_something_else()

HTML 양식 없이 AJAX를 사용하는 페이지 보호

AJAX를 통해 POST 요청을 하며, 필수 CSRF 쿠키가 전송되도록 하는 :ttag:`csrf_token`이 포함된 HTML 양식이 없는 페이지.

솔루션: 페이지를 보내는 뷰에서 :func:`~django.views.decorators.csrf.ensure_csrf_cookie`를 사용하세요.

재사용 가능한 애플리케이션에서 CSRF 보호

개발자가 CsrfViewMiddleware``를 있기 때문에 contrib apps와 관련된 모든 뷰들은 CSRF에 대한 이러한 애플리케이션의 보안을 보장하기 위해 ``csrf_protect 데코레이터를 사용합니다. 동일한 보장을 원하는 다른 재사용 가능한 앱의 개발자도 자신의 뷰에 csrf_protect 데코레이터를 사용하는 것이 좋습니다.

Back to Top