با استفاده از CSRF داخلی جنگو از وب سایت خود در برابر یک حفره امنیتی بسیار رایج محافظت کنید.
جنگو یک چارچوب وب پایتون است که می توانید از آن برای ساخت برنامه های وب امن استفاده کنید. این ویژگی های بسیاری را برای کمک به توسعه دهندگان در زمینه امنیت ارائه می دهد. یکی از این ویژگیها توکنهای CSRF است که برای محافظت از فرمها در برابر حملات جعل درخواست Cross-Site ضروری است.
توکن CSRF چیست؟
توکن CSRF یک ویژگی امنیتی است که از برنامه های کاربردی وب در برابر حملات جعل درخواست متقابل (CSRF) محافظت می کند. این به سرور برنامه اجازه میدهد بررسی کند که فرم ارسالی از یک مرورگر معتبر است یا یک هکر آن را جعل کرده است.
توکن های CSRF ورودی های فرمی هستند که یک جلسه کاربر را پیگیری می کنند. چارچوب برنامه کاربردی وب سمت سرور یک وب سایت معمولاً توکن های CSRF را برای هر جلسه کاربر منحصر به فرد تولید می کند. هر زمان که کاربر فرمی را ارسال می کند، سرور بررسی می کند که آیا نشانه صحیح است. توکنهای CSRF معمولاً از رشتهها و اعداد تصادفی تشکیل شدهاند که باعث میشود مقادیر آنها غیرقابل پیشبینی باشد.
تولید توکن CSRF در جنگو
تابع get_token() جنگو به طور تصادفی توکن های CSRF را تولید می کند. برای یافتن این تابع، به فایل csrf.py در محیط مجازی پایتون خود بروید. ساختار پوشه باید به شکل زیر باشد:
env/
└── Lib/
└── site-packages/
└── django/
└── middleware/
└── csrf.py
در داخل این فایل، تابع get_token() را خواهید دید که توکن را برمی گرداند. جنگو از پوشش داده برای محافظت از ارزش توکن در برابر هکرها استفاده می کند.
به طور پیش فرض، جنگو با افزودن django.middleware.csrf.CsrfViewMiddleware در لیست MIDDLEWARE فایل settings.py، حفاظت CSRF را برای سایت شما فعال می کند. تنها کاری که باید انجام دهید این است که {% csrf_token %} را به فرمهای POST خود اضافه کنید. بدون افزودن {% csrf_token %}، هنگام ارسال فرم با خطای 403 (ممنوع) مواجه خواهید شد.
هنگامی که {% csrf_token %} را به فرم خود اضافه می کنید، به طور خودکار یک فیلد ورودی مخفی با نام csrfmiddlewaretoken ایجاد می کند که حاوی مقدار توکن CSRF ماسک شده است. سرور از این مقدار برای تعیین معتبر بودن فرم ارسالی استفاده می کند. می توانید با مشاهده منبع صفحه یا با استفاده از ویژگی ابزارهای توسعه دهنده مرورگر خود، ارزش این فیلد پنهان را بررسی کنید.
چگونه توکنهای CSRF در جنگو کار میکنند
هنگامی که سایت خود را با فرم راه اندازی می کنید، جنگو به طور خودکار یک کوکی مرورگر به نام csrftoken ایجاد می کند. این کوکی فعالیت کاربر در سایت را پیگیری می کند و هر کاربر را به طور منحصر به فرد شناسایی می کند.
هنگامی که کاربر فرم را ارسال می کند، سرور مقدار کوکی را با مقدار csrfmiddlewaretoken در فیلد ورودی مخفی مقایسه می کند. اگر این مقادیر مطابقت داشته باشند، سرور فرم را با موفقیت پردازش می کند، در غیر این صورت یک خطا ایجاد می کند.
در نگاه اول، مقادیر کوکی و csrfmiddlewaretoken متفاوت به نظر می رسد. این عمدی است و یک لایه حفاظتی اضافی به توکن CSRF اضافه می کند. توکن CSRF با کوکی به صورت زیر مقایسه می شود:
- تابع get_token() رمز CSRF را قبل از ارسال به فیلد ورودی ماسک می کند.
- هنگامی که فرم ارسال می شود، رمز CSRF با کمک کلید مخفی در فایل تنظیمات، از ماسک خارج می شود.
- توکن بدون ماسک با کوکی جلسه مقایسه می شود.
- اگر مقادیر یکسان باشند، فرم پردازش می شود. در غیر این صورت سرور یک خطا برمی گرداند.
برای جلوگیری از سرقت توکن CSRF توسط هکرها، جنگو هر بار که یک جلسه کاربر را شروع می کند آن را تجدید می کند.
ایجاد توکن های سفارشی CSRF
اگرچه جنگو با افزودن {% csrf_token %}، محافظت از فرمهای شما را آسان میکند، اما تولید توکنهای CSRF و افزودن دستی آنها به فرمهای شما نیز امکانپذیر است. برای این کار تابع get_token() را وارد کنید:
from django.middleware.csrf import get_token
به نظر شما، می توانید توکن CSRF را به صورت زیر تولید کنید:
def view_name(request):
csrf_token = get_token(request)
# perform view logic
context = {
"csrf_token": csrf_token
}
return render(request, 'app_name/template.html', context=context)
در قالب HTML خود، می توانید به صورت دستی تگ ورودی خود را اضافه کنید و csrf_token را به این صورت به آن اضافه کنید:
<form method="POST" >
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
{{form.as_p}}
<button type="submit" class="btn btn-outline-secondary">Add Book</button>
</form>
همچنین، میتوانید فیلد ورودی مخفی را از نماهای خود به صورت زیر ایجاد کنید:
def your_view(request):
csrf_token = get_token(request)
csrf_token_html = '<input type="hidden" name="csrfmiddlewaretoken" value="{}" />'.format(csrf_token)
# perform view logic
context = {
"csrf_token": csrf_token_html
}
return render(request, 'app_name/template.html', context=context)
سپس می توانید آن را به شکل زیر به قالب HTML خود اضافه کنید:
<form method="POST" >
{{ csrf_token_html|safe }}
{{form.as_p}}
<button type="submit" class="btn btn-outline-secondary">Add Book</button>
</form>
اگر میخواهید کاملاً محافظت CSRF فرم خود را کنترل کنید، میتوانید این کار را با مقایسه کد CSRF خود با کوکی ذخیره شده در مرورگر انجام دهید. بر اساس نتایج مقایسه، می توانید فرم ارسالی را هر طور که می خواهید انجام دهید. در اینجا یک مثال است:
from django.shortcuts import render
from django.middleware.csrf import get_token, _unmask_cipher_token
from django.utils.crypto import constant_time_compare
def your_view(request):
# Generate a custom CSRF token
csrf_token = get_token(request)
csrf_cookie = request.COOKIES.get('csrftoken')
# unmask csrf token
unmasked_csrf_token = _unmask_cipher_token(csrf_token)
# Compare the tokens
if not constant_time_compare(unmasked_csrf_token, csrf_cookie):
# Handle the case where the tokens don't match
pass
else:
# Handle the case where the tokens match
pass
# Render the template
context = {
'csrf_token': csrf_token,
}
return render(request, 'app_name/template.html', context=context)
این قطعه کد csrf_cookie را از شی درخواست HTTP بازیابی می کند. سپس از تابع _unmask_cipher_token() برای از بین بردن ماسک csrf_token استفاده می کند.
یک دستور شرطی مقادیر csrf_cookie بازیابی شده و csrf_token بدون ماسک را مقایسه می کند. این مقایسه از تابع konstant_time_compare برای محافظت در برابر سوء استفاده های زمان بندی استفاده می کند. شما می توانید منطق خود را بر اساس نتیجه مقایسه بنویسید.
غیرفعال کردن CSRF Protection در جنگو
حتی اگر جنگو یک پیشفرض برای حفاظت CSRF ایجاد کرده است، در صورت تمایل میتوانید آن را در پروژه خود غیرفعال کنید. دو راه برای انجام این کار وجود دارد:
- غیرفعال کردن حفاظت CSRF در کل وب سایت شما.
- غیرفعال کردن حفاظت CSRF در یک نمای خاص.
غیرفعال کردن محافظت CSRF در کل وب سایت شما
برای غیرفعال کردن محافظت CSRF جنگو در وب سایت خود، فقط باید میان افزار CSRF را از فایل تنظیمات خود حذف کنید. در فایل تنظیمات خود، فهرستی به نام MIDDLEWARE را پیدا کنید. در داخل لیست، این مورد را جستجو کنید:
'django.middleware.csrf.CsrfViewMiddleware',
هنگامی که آن را پیدا کردید، باید آن را از کد خود حذف کنید تا حفاظت CSRF پیشفرض جنگو را غیرفعال کنید.
غیرفعال کردن محافظت CSRF در یک نمای خاص
اگر فقط میخواهید محافظت CSRF را در یک نمای جنگو خاص غیرفعال کنید، از دکوراتور @csrf_exempt استفاده کنید. در اینجا یک قطعه کد برای نشان دادن وجود دارد:
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def view_name(request):
# perform view logic
pass
دکوراتور @csrf_exempt تنها یکی از چندین مورد مرتبط با حفاظت CSRF در جنگو است. شما می توانید در مورد بقیه در مرجع CSRF جنگو بخوانید.
محافظت CSRF را در وب سایت خود غیرفعال نکنید
اگرچه جنگو این امکان را فراهم میکند، اما غیرفعال کردن مکانیسم حفاظتی داخلی CSRF در جنگو توصیه نمیشود. انجام این کار سایت شما را در برابر حملات CSRF آسیب پذیر می کند و در نهایت بر کاربران برنامه شما تأثیر منفی می گذارد.
مگر اینکه شما یک توسعه دهنده با تجربه هستید که می دانید چگونه یک مکانیسم حفاظتی سفارشی CSRF را پیاده سازی کنید، باید با جایگزین ارائه شده توسط جنگو کار کنید.