장고의 CSRF 보호를 사용하는 방법¶
당신의 뷰에서 CSRF 보호를 활용하려면 다음 단계를 따르십시오:
CSRF 미들웨어는
MIDDLEWARE
설정에서 기본적으로 활성화되어 있습니다. 해당 설정을 덮어쓰는 경우에는, CSRF 공격이 처리되었다고 가정하는 모든 뷰 미들웨어 앞에 ``’django.middleware.csrf.CsrfViewMiddleware’``가 와야 함을 기억하십시오.사용하지 않도록 설정한 경우(권장하지 않음), 보호하려는 특정 뷰에서 :func:`~django.views.decorators.csrf.csrf_protect`를 사용할 수 있습니다(아래 참조).
POST 양식을 사용하는 모든 템플릿에서, 양식이 내부 URL용인 경우
<form>
요소 내부에csrf_token
태그를 사용하세요. 예:<form method="post">{% csrf_token %}
외부 URL을 대상으로 하는 POST 양식에 대해서는 이렇게 할 수 없습니다. CSRF 토큰이 누출되어 취약점이 발생할 수 있기 때문입니다.
해당 뷰 함수에서
render
함수, 제네릭 뷰, 또는 contrib apps를 사용하는 경우, 이들은 모두 ``RequestContext``를 사용하므로 확인할 필요가 업습니다.
AJAX와 함께 CSRF 보호 사용¶
위의 방법을 AJAX POST 요청에 사용할 수 있지만 몇 가지 불편한 점이 있습니다: 모든 POST 요청에 POST 데이터로 CSRF 토큰을 전달해야 합니다. 이러한 불편함 때문에, 다른 대체 방법이 있습니다: 각 XMLHttpRequest에서 사용자 지정 X-CSRFToken
헤더(CSRF_HEADER_NAME
설정에 지정된 대로)를 CSRF 토큰 값으로 설정합니다. 많은 JavaScript 프레임워크가 모든 요청에 대해 헤더를 설정할 수 있도록 하는 후크를 제공하기 때문에 이 방식이 종종 더 쉽습니다.
먼저, CSRF 토큰을 받아야 합니다. 그 방법은 CSRF_USE_SESSIONS
및 CSRF_COOKIE_HTTPONLY
설정이 활성화되어 있는지 여부에 따라 다릅니다.
CSRF_USE_SESSIONS
및 :setting:`CSRF_COOKIE_HTTPONLY`가 ``False``인 경우 토큰 획득¶
토큰의 권장 원본은 csrftoken
쿠키이며, 이는 위에서 설명한 대로 뷰에 대해 CSRF 보호를 활성화한 경우 자동으로 설정됩니다.
CSRF 토큰 쿠키의 이름은 기본적으로 ``csrftoken``이지만 CSRF_COOKIE_NAME
설정을 통해 쿠키 이름을 설정할 수 있습니다.
다음과 같이 토큰을 획득할 수 있습니다:
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
위의 코드는 ``getCookie``를 대체하기 위한 `JavaScript 쿠키 라이브러리 <https://github.com/js-cookie/js-cookie/>`_를 사용하여 단순화할 수 있습니다.
const csrftoken = Cookies.get('csrftoken');
참고
CSRF 토큰은 템플릿에서 :ttag:`csrf_token`을 사용하여 명시적으로 include된 경우에만 DOM에도 마스크된 형태로 존재합니다. 쿠키에는 마스크되지 않은 표준 토큰이 포함되어 있습니다. :class:`~django.middleware.csrf.CsrfViewMiddleware`는 둘 중 하나를 수락합니다. 그러나 BREACH`_ 공격으로부터 보호하기 위해서는 마스킹된 토큰을 사용하는 것이 좋습니다.
경고
만약 뷰가 csrf_token
템플릿 태그가 포함된 템플릿을 렌더링하지 않는 경우, 장고는 CSRF 토큰 쿠키를 설정하지 않을 수 있습니다. 이는 양식이 페이지에 동적으로 추가되는 경우에는 일반적인 설정입니다. 이 경우, 장고는 쿠키 설정을 강제하는 뷰 데코레이터를 제공합니다: ensure_csrf_cookie()
.
CSRF_USE_SESSIONS
또는 :setting:`CSRF_COOKIE_HTTPONLY`가 ``True``인 경우 토큰 획득¶
CSRF_USE_SESSIONS
또는 :setting:`CSRF_COOKIE_HTTPONLY`를 활성화하는 경우, HTML에 CSRF 토큰을 포함하고 JavaScript를 사용하여 DOM에서 토큰을 읽어야 합니다.
{% csrf_token %}
<script>
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
</script>
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()
재사용 가능한 애플리케이션에서 CSRF 보호¶
개발자가 CsrfViewMiddleware``를 끌 수 있기 때문에 contrib apps와 관련된 모든 뷰들은 CSRF에 대한 이러한 애플리케이션의 보안을 보장하기 위해 ``csrf_protect
데코레이터를 사용합니다. 동일한 보장을 원하는 다른 재사용 가능한 앱의 개발자도 자신의 뷰에 csrf_protect
데코레이터를 사용하는 것이 좋습니다.