djang-csrf 원본 분석
CSRF(Cross Site Request Forgery, 크로스 스테이션 요청 변조)는 네트워크의 공격 방식입니다.
프로세스 분석
django 중간부품 통과 django.middleware.csrf.CsrfView Middleware를 사용하면 이 종류의 CsrfView Middleware를 볼 수 있습니다. 만약에 우리가django로 프로젝트를 뛰고 페이지를 처음 열면processresponse에서 쿠키를 설정합니다. 쿠키의 이름은 csrftoken이고 settings에서 CSRF 를 설정할 수 있습니다.COOKIE_NAME, 폼을 제출해야 합니다. 프로세스요청이post 방법으로 검출되었습니다. 쿠키의 csrftoken과 폼에서 제출한 csrfmiddlewaretoken 값을 검사합니다. 검사가 통과되면 계속됩니다. 403로 되돌아오지 않고 요청이 실패합니다.
코드 해석
csrf 어떻게 생성
CSRF_SECRET_LENGTH = 32
CSRF_TOKEN_LENGTH = 2 * CSRF_SECRET_LENGTH
CSRF_ALLOWED_CHARS = string.ascii_letters + string.digits
def _get_new_csrf_string(): # 64 ( )
return get_random_string(CSRF_SECRET_LENGTH, allowed_chars=CSRF_ALLOWED_CHARS)
def get_token(request):
if "CSRF_COOKIE" not in request.META:
csrf_secret = _get_new_csrf_string()
request.META["CSRF_COOKIE"] = _salt_cipher_secret(csrf_secret)
else:
csrf_secret = _unsalt_cipher_token(request.META["CSRF_COOKIE"])
request.META["CSRF_COOKIE_USED"] = True
return _salt_cipher_secret(csrf_secret)
def _salt_cipher_secret(secret):
"""
Given a secret (assumed to be a string of CSRF_ALLOWED_CHARS), generate a
token by adding a salt and using it to encrypt the secret.
"""
salt = _get_new_csrf_string() # salt
chars = CSRF_ALLOWED_CHARS
pairs = zip((chars.index(x) for x in secret), (chars.index(x) for x in salt)) # salt secret
cipher = ''.join(chars[(x + y) % len(chars)] for x, y in pairs) # chars chars
return salt + cipher # salt cipher
csrf 어떻게 검사했는지
def constant_time_compare(val1, val2):
"""Return True if the two strings are equal, False otherwise."""
return hmac.compare_digest(force_bytes(val1), force_bytes(val2))
# force_bytes
def _compare_salted_tokens(request_csrf_token, csrf_token):
# Assume both arguments are sanitized -- that is, strings of
# length CSRF_TOKEN_LENGTH, all CSRF_ALLOWED_CHARS.
return constant_time_compare(
_unsalt_cipher_token(request_csrf_token),
_unsalt_cipher_token(csrf_token),
)
예를 들다.
쿠키의 csrftoken: 8JDrBEx0K2ia0KFGaYGCg9mYmzYANFMtqcrZsq3KMPrZJAwKXgjrnxH6T17TJol3
form의 csrfmiddlewaretoken:dGZNEIV1rwUbMJA4EDRHaJGHydZLVEFv9NlvurLtj30vzr8rVuwh71PeomiHEDf
위의 체크섬 방법을 사용하여 다음을 수행합니다.
import hmac
import string
import datetime
from decimal import Decimal
_PROTECTED_TYPES = (
type(None), int, float, Decimal, datetime.datetime, datetime.date, datetime.time,
)
CSRF_SECRET_LENGTH = 32
CSRF_ALLOWED_CHARS = string.ascii_letters + string.digits
def is_protected_type(obj):
"""Determine if the object instance is of a protected type.
Objects of protected types are preserved as-is when passed to
force_text(strings_only=True).
"""
return isinstance(obj, _PROTECTED_TYPES)
def force_bytes(s, encoding='utf-8', strings_only=False, errors='strict'):
"""
Similar to smart_bytes, except that lazy instances are resolved to
strings, rather than kept as lazy objects.
If strings_only is True, don't convert (some) non-string-like objects.
"""
# Handle the common case first for performance reasons.
if isinstance(s, bytes):
if encoding == 'utf-8':
return s
else:
return s.decode('utf-8', errors).encode(encoding, errors)
if strings_only and is_protected_type(s):
return s
if isinstance(s, memoryview):
return bytes(s)
return str(s).encode(encoding, errors)
def constant_time_compare(val1, val2):
"""Return True if the two strings are equal, False otherwise."""
return hmac.compare_digest(force_bytes(val1), force_bytes(val2))
def _unsalt_cipher_token(token):
"""
Given a token (assumed to be a string of CSRF_ALLOWED_CHARS, of length
CSRF_TOKEN_LENGTH, and that its first half is a salt), use it to decrypt
the second half to produce the original secret.
"""
salt = token[:CSRF_SECRET_LENGTH]
token = token[CSRF_SECRET_LENGTH:]
chars = CSRF_ALLOWED_CHARS
pairs = zip((chars.index(x) for x in token), (chars.index(x) for x in salt))
secret = ''.join(chars[x - y] for x, y in pairs) # Note negative values are ok
return secret
# force_bytes
def _compare_salted_tokens(request_csrf_token, csrf_token):
# Assume both arguments are sanitized -- that is, strings of
# length CSRF_TOKEN_LENGTH, all CSRF_ALLOWED_CHARS.
return constant_time_compare(
_unsalt_cipher_token(request_csrf_token),
_unsalt_cipher_token(csrf_token),
)
csrfmiddlewaretoken = "dGZNEIV1rwUbMJA4EDRHaJGHHydZLVEFv9NlvurLtj30vzr8rVuwh71Pe0miHEDf"
csrf_token = "8JDrBEx0K2ia0KFGaYGCg9mYmzYANFMtqcrZsq3KMPrZJAwKXgjrnxH6T17TJoL3"
print(_compare_salted_tokens(csrfmiddlewaretoken, csrf_token))
# True
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.