교차 사이트 요청 위조 방지 ¶
CSRF 미들웨어 및 템플릿 태그는 교차 사이트 요청 위조에 대해 사용하기 쉬운 보호 기능을 제공합니다 . 이러한 유형의 공격은 브라우저에서 악성 사이트를 방문하는 로그인한 사용자의 자격 증명을 사용하여 웹 사이트에서 일부 작업을 수행하도록 의도된 링크, 양식 버튼 또는 일부 JavaScript가 악의적인 웹 사이트에 포함되어 있을 때 발생합니다. 공격 사이트가 사용자의 브라우저를 속여 다른 사람의 자격 증명을 사용하여 사이트에 로그인하도록 속이는 관련 유형의 공격인 ‘로그인 CSRF’도 다룹니다.
CSRF 공격에 대한 첫 번째 방어는 GET 요청(및 다음에서 정의한 기타 ‘안전한’ 방법)을 보장하는 것입니다.RFC 9110#section-9.2.1 ) 부작용이 없습니다. POST, PUT 및 DELETE와 같은 ‘안전하지 않은’ 메서드를 통한 요청은 Django의 CSRF 보호 사용 방법 에 설명된 단계로 보호할 수 있습니다.
작동 방식 ¶
CSRF 보호는 다음 사항을 기반으로 합니다.
- 다른 사이트에서 액세스할 수 없는 임의의 비밀 값인 CSRF 쿠키입니다.
CsrfViewMiddleware
가 호출될 때마다 응답과 함께 이 쿠키를 보냅니다django.middleware.csrf.get_token()
. 다른 경우에도 보낼 수 있습니다. 보안상의 이유로 암호 값은 사용자가 로그인할 때마다 변경됩니다. - 나가는 모든 POST 양식에 있는 ‘csrfmiddlewaretoken’이라는 이름의 숨겨진 양식 필드입니다.BREACH 공격 으로부터 보호하기 위해 이 필드의 값은 단순히 비밀이 아닙니다. 마스크를 사용하여 각 응답마다 다르게 스크램블됩니다. 마스크는 에 대한 모든 호출에서 무작위로 생성되므로
get_token()
양식 필드 값은 매번 다릅니다.이 부분은 템플릿 태그에 의해 수행됩니다. - HTTP GET, HEAD, OPTIONS 또는 TRACE를 사용하지 않는 모든 수신 요청의 경우 CSRF 쿠키가 존재해야 하며 ‘csrfmiddlewaretoken’ 필드가 존재하고 정확해야 합니다. 그렇지 않으면 사용자에게 403 오류가 표시됩니다.’csrfmiddlewaretoken’ 필드 값을 검증할 때 전체 토큰이 아닌 비밀만 쿠키 값의 비밀과 비교됩니다. 이를 통해 끊임없이 변화하는 토큰을 사용할 수 있습니다. 각 요청은 자체 토큰을 사용할 수 있지만 비밀은 모두에게 공통으로 남아 있습니다.이 검사는 에 의해 수행됩니다
CsrfViewMiddleware
. CsrfViewMiddleware
현재 호스트 및 설정에 대해 브라우저에서 제공하는 경우 Origin 헤더를 확인합니다CSRF_TRUSTED_ORIGINS
. 이는 하위 도메인 간 공격에 대한 보호 기능을 제공합니다.- 또한 HTTPS 요청의 경우
Origin
헤더가 제공되지 않으면CsrfViewMiddleware
엄격한 리퍼러 확인을 수행합니다. 즉, 하위 도메인이 귀하의 도메인에서 쿠키를 설정하거나 수정할 수 있더라도 해당 요청이 귀하의 정확한 도메인에서 오지 않기 때문에 사용자가 애플리케이션에 게시하도록 강제할 수 없습니다.Set-Cookie
이것은 또한 HTTP 헤더가 (불행하게도) 클라이언트가 HTTPS에서 사이트와 통신할 때에도 허용된다는 사실 때문에 세션 독립적인 비밀을 사용할 때 HTTPS에서 가능한 중간자 공격을 해결합니다. (HTTP에서는 헤더의 존재가Referer
충분히 신뢰할 수 없기 때문에 HTTP 요청에 대해 리퍼러 확인이 수행되지 않습니다.)설정이 지정 되면CSRF_COOKIE_DOMAIN
리퍼러가 설정과 비교됩니다. 선행 점을 포함하여 하위 도메인 간 요청을 허용할 수 있습니다. 예를 들어 및 의 POST 요청을 허용합니다 . 설정이 지정되지 않은 경우 리퍼러는 HTTP 헤더와 일치해야 합니다.CSRF_COOKIE_DOMAIN = '.example.com'
www.example.com
api.example.com
Host
허용된 리퍼러를 현재 호스트 또는 쿠키 도메인 이상으로 확장하는 것은CSRF_TRUSTED_ORIGINS
설정을 통해 수행할 수 있습니다.
Django 4.1에서 변경됨:
이전 버전에서는 CSRF 쿠키 값이 마스킹되었습니다.
이렇게 하면 신뢰할 수 있는 도메인에서 시작된 양식만 데이터를 POST하는 데 사용할 수 있습니다.
GET 요청(및 ‘안전’으로 정의된 기타 요청)을 의도적으로 무시합니다.RFC 9110#섹션-9.2.1 ). 이러한 요청에는 잠재적으로 위험한 부작용이 없어야 하므로 GET 요청을 통한 CSRF 공격은 무해해야 합니다.RFC 9110#section-9.2.1은 POST, PUT 및 DELETE를 ‘안전하지 않음’으로 정의하며, 다른 모든 방법도 최대한의 보호를 위해 안전하지 않은 것으로 가정합니다.
CSRF 보호는 중간자 공격으로부터 보호할 수 없으므로 HTTP Strict Transport Security 와 함께 HTTPS를 사용하십시오 . 또한 HOST 헤더의 유효성 검사를 가정 하고 사이트에 교차 사이트 스크립팅 취약점이 없다고 가정합니다 (XSS 취약점으로 인해 이미 공격자가 CSRF 취약점이 허용하는 모든 작업을 수행할 수 있기 때문에 훨씬 더 나쁩니다).
Referer
헤더 제거
리퍼러 URL이 타사 사이트에 공개되지 않도록 하려면 사이트 태그에서 리퍼러를 비활성화<a>
할 수 있습니다 . 예를 들어 태그를 사용하거나 헤더를 포함 할 수 있습니다 . HTTPS 요청에 대한 CSRF 보호의 엄격한 리퍼러 검사로 인해 이러한 기술은 ‘안전하지 않은’ 메서드를 사용하는 요청에서 CSRF 실패를 일으킵니다. 대신 타사 사이트에 대한 링크와 같은 대안을 사용하십시오.<meta name="referrer" content="no-referrer">
Referrer-Policy: no-referrer
<a rel="noreferrer" ...>"
Limitations¶
사이트 내의 하위 도메인은 전체 도메인의 클라이언트에서 쿠키를 설정할 수 있습니다. 쿠키를 설정하고 해당 토큰을 사용하면 하위 도메인이 CSRF 보호를 우회할 수 있습니다. 이를 방지하는 유일한 방법은 신뢰할 수 있는 사용자가 하위 도메인을 제어하는지 확인하는 것입니다(또는 최소한 쿠키를 설정할 수 없음). CSRF가 없더라도 세션 고정과 같이 신뢰할 수 없는 당사자에게 하위 도메인을 제공하는 것을 나쁜 생각으로 만드는 다른 취약성이 있으며 이러한 취약성은 현재 브라우저에서 쉽게 수정할 수 없습니다.
Utilities¶
아래 예에서는 함수 기반 보기를 사용한다고 가정합니다. 클래스 기반 보기로 작업하는 경우 클래스 기반 보기 장식을 참조할 수 있습니다 .csrf_exempt
( 보기 ) ¶
이 데코레이터는 뷰를 미들웨어가 보장하는 보호에서 제외되는 것으로 표시합니다. 예:
from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt @csrf_exempt def my_view(request): return HttpResponse("Hello world")
csrf_protect
( 보기 ) ¶
CsrfViewMiddleware
뷰를 보호하는 데코레이터 .
용법:
from django.shortcuts import render from django.views.decorators.csrf import csrf_protect @csrf_protect def my_view(request): c = {} # ... return render(request, "a_template.html", c)
requires_csrf_token
( 보기 ) ¶
일반적으로 유사 항목이 실행 csrf_token
되지 않으면 템플릿 태그가 작동하지 않습니다 . 보기 데코레이터를 사용하여 템플릿 태그가 작동하는지 확인할 수 있습니다. 이 데코레이터는 와 유사하게 작동 하지만 들어오는 요청을 거부하지 않습니다.CsrfViewMiddleware.process_view
csrf_protect
requires_csrf_token
csrf_protect
예:
from django.shortcuts import render from django.views.decorators.csrf import requires_csrf_token @requires_csrf_token def my_view(request): c = {} # ... return render(request, "a_template.html", c)
ensure_csrf_cookie
( 보기 ) ¶
이 데코레이터는 뷰가 CSRF 쿠키를 보내도록 합니다.
Settings¶
Django의 CSRF 동작을 제어하기 위해 여러 설정을 사용할 수 있습니다.
CSRF_COOKIE_AGE
CSRF_COOKIE_DOMAIN
CSRF_COOKIE_HTTPONLY
CSRF_COOKIE_NAME
CSRF_COOKIE_PATH
CSRF_COOKIE_SAMESITE
CSRF_COOKIE_SECURE
CSRF_FAILURE_VIEW
CSRF_HEADER_NAME
CSRF_TRUSTED_ORIGINS
CSRF_USE_SESSIONS
자주 묻는 질문 ¶
임의의 CSRF 토큰 쌍(쿠키 및 POST 데이터)을 게시하는 것이 취약점입니까? ¶
아니요, 의도적으로 설계된 것입니다. 중간자 공격이 없으면 공격자가 CSRF 토큰 쿠키를 피해자의 브라우저에 보낼 수 있는 방법이 없으므로 공격에 성공하려면 XSS 또는 이와 유사한 방법을 통해 피해자의 브라우저 쿠키를 가져와야 합니다. 공격자는 일반적으로 CSRF 공격이 필요하지 않습니다.
일부 보안 감사 도구는 이를 문제로 표시하지만 앞서 언급한 것처럼 공격자는 사용자 브라우저의 CSRF 쿠키를 훔칠 수 없습니다. Firebug, Chrome 개발 도구 등을 사용하여 자신의 토큰을 “도용”하거나 수정하는 것은 취약점이 아닙니다.
Django의 CSRF 보호가 기본적으로 세션에 연결되지 않는 것이 문제입니까? ¶
아니요, 의도적으로 설계된 것입니다. CSRF 보호를 세션에 연결하지 않으면 세션이 없는 익명 사용자의 제출을 허용하는 페이스트빈 과 같은 사이트에서 보호를 사용할 수 있습니다 .
사용자 세션에 CSRF 토큰을 저장하려면 CSRF_USE_SESSIONS
설정을 사용하십시오.
사용자가 로그인한 후 CSRF 유효성 검사 실패가 발생하는 이유는 무엇입니까? ¶
보안상의 이유로 CSRF 토큰은 사용자가 로그인할 때마다 순환됩니다. 로그인 전에 생성된 양식이 있는 모든 페이지에는 오래되고 잘못된 CSRF 토큰이 있으므로 다시 로드해야 합니다. 이는 사용자가 로그인 후 뒤로 버튼을 사용하거나 다른 브라우저 탭에 로그인하는 경우에 발생할 수 있습니다.