امنیت در جنگو: تجربیات شخصی و راه‌های ارتقا

راهنمای جامع امنیت در جنگو: از تئوری تا عمل

به عنوان یک برنامه‌نویس بک‌اند که سال‌ها با جنگو کار کرده‌ام، همیشه امنیت یکی از دغدغه‌های اصلی‌ام بوده است. در این پست، تجربیات شخصی و روش‌هایی را که برای افزایش امنیت وب‌سایت‌های جنگو به کار گرفته‌ام، با شما به اشتراک می‌گذارم.

بخش اول: مبانی امنیت جنگو

1. محافظت در برابر حملات رایج

**CSRF (جعل درخواست بین سایت‌ها)**
جنگو به‌صورت پیش‌فرض از شما در برابر حملات CSRF محافظت می‌کند، اما باید اطمینان حاصل کنید که:
- از `{% csrf_token %}` در تمام فرم‌ها استفاده می‌کنید
- میدل‌ویر مربوط به CSRF (`django.middleware.csrf.CsrfViewMiddleware`) فعال باشد

**XSS (اجرای اسکریپت‌های مخرب)**
همیشه از فیلترهای خودکار جنگو (`{{ variable | escape }}`) استفاده کنید یا از `mark_safe` تنها زمانی که مطمئن هستید محتوا امن است. همچنین از کتابخانه‌هایی مثل `django-bleach` برای پاکسازی HTML ورودی کاربر بهره ببرید.

**SQL Injection**
جنگو ORM قدرتمندی دارد که به‌صورت پیش‌فرض از تزریق SQL جلوگیری می‌کند، اما:
- هرگز از رشته‌های فرمت‌بندی شده استفاده نکنید: `f"SELECT ... WHERE user={user_id}"`
- همیشه از پارامترهای امن ORM بهره ببرید: `User.objects.filter(id=user_id)`

2. مدیریت احراز هویت و مجوزها

**احراز هویت (Authentication)**
- از پسوردهای قوی اطمینان حاصل کنید (جنگو به‌صورت پیش‌فرض از الگوریتم‌های ایمن استفاده می‌کند)
- برای افزایش امنیت، از ورود دو مرحله‌ای (2FA) با کتابخانه‌هایی مثل `django-otp` استفاده کنید

**مجوزها (Permissions & Authorization)**
- همیشه از دکوراتورهای `@login_required` و `@permission_required` استفاده کنید
- برای سیستم‌های پیچیده‌تر، از دسترسی‌های سطح ریز (Object-Level Permissions) با `django-guardian` بهره ببرید

3. امنیت سرور و تنظیمات جنگو

**تنظیمات settings.py**
- `DEBUG=False` در محیط تولید! (عدم نمایش خطاهای حساس)
- `SECRET_KEY` را در فایل‌های محیطی (`.env`) نگه دارید و آن را در Git کامیت نکنید
- از `ALLOWED_HOSTS` به‌درستی استفاده کنید و فقط دامنه‌های معتبر را لیست کنید

**محدود کردن دسترسی‌ها**
- از `django-csp` (Content Security Policy) برای جلوگیری از اجرای اسکریپت‌های خارجی استفاده کنید
- HTTPS اجباری با `SECURE_SSL_REDIRECT = True` و تنظیم HSTS

4. لاگ‌گیری و مانیتورینگ
- از `django-admin-honeypot` برای تشخیص حمله‌های Brute-Force به صفحه ادمین استفاده کنید
- لاگ‌گیری از فعالیت‌های کاربران با `django-auditlog`
- مانیتورینگ لاگین‌های ناموفق با `axes`

5. آپدیت مداوم
- همیشه آخرین نسخه پایدار جنگو را استفاده کنید
- کتابخانه‌ها را به‌روز نگه دارید (`pip list --outdated`)

---

بخش دوم: امنیت جنگو با مثال‌های عملی

درک مفاهیم امنیتی با مثال‌های واقعی بسیار ساده‌تر می‌شود. در ادامه، همان نکات قبلی را با کدهای عملی توضیح می‌دهم تا دقیقاً بدانید چگونه پیاده‌سازی کنید.

1. محافظت در برابر CSRF (مثال عملی)

جنگو به صورت پیش‌فرض از CSRF محافظت می‌کند، اما باید مطمئن شوید فرم‌های شما از توکن استفاده می‌کنند:

**❌ نادرست (عدم استفاده از CSRF Token)**
```html
<form method="post">
<input type="text" name="username">
<button type="submit">ارسال</button>
</form>
```

**✅ درست (استفاده از {% csrf_token %})**
```html
<form method="post">
{% csrf_token %} <!-- این خط حیاتی است! -->
<input type="text" name="username">
<button type="submit">ارسال</button>
</form>
```

اگر `CsrfViewMiddleware` فعال نباشد، باید از دکوراتور `@csrf_protect` استفاده کنید:

```python
from django.views.decorators.csrf import csrf_protect

@csrf_protect
def my_view(request):
...
```

2. جلوگیری از XSS (مثال عملی)

**❌ نادرست (اجازه اجرای اسکریپت‌های مخرب)**
```html
<p>{{ user_input }}</p> <!-- اگر user_input شامل <script> باشد، اجرا می‌شود! -->
```

**✅ درست (استفاده از فیلتر escape یا mark_safe با احتیاط)**
```html
<p>{{ user_input | escape }}</p>
```

اگر مطمئن هستید محتوا امن است (مثل متن ذخیره‌شده در دیتابیس توسط شما):

```python
from django.utils.safestring import mark_safe

safe_content = mark_safe("<b>متن ایمن</b>") # فقط اگر واقعاً مطمئن هستید!
```

3. جلوگیری از SQL Injection (مثال‌های ORM)

**❌ نادرست (استفاده از کوئری ناامن)**
```python
# خطرناک! امکان تزریق SQL وجود دارد.
query = f"SELECT * FROM users WHERE username = '{username}'"
users = User.objects.raw(query)
```

**✅ درست (استفاده از ORM جنگو یا پارامترهای امن)**
```python
# ایمن (ORM جنگو)
users = User.objects.filter(username=username)

# یا اگر مجبور به استفاده از SQL خام هستید:
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM users WHERE username = %s", [username])
```

4. مدیریت احراز هویت (ورود دو مرحله‌ای - 2FA)

**نصب کتابخانه:**
```bash
pip install django-otp
```

**تنظیمات settings.py:**
```python
INSTALLED_APPS = [
...
'django_otp',
'django_otp.plugins.otp_totp', # برای کدهای موقت (TOTP)
]
```

**اضافه کردن 2FA به یک ویو:**
```python
from django.contrib.auth.decorators import login_required
from django_otp.decorators import otp_required

@login_required
@otp_required # فقط بعد از تأیید دو مرحله‌ای اجازه دسترسی می‌دهد
def secure_view(request):
return HttpResponse("این صفحه بسیار امن است!")
```

5. تنظیمات امنیتی settings.py (مثال‌های مهم)

```python
# در production این‌ها را تنظیم کنید!
DEBUG = False # خطاها نمایش داده نمی‌شوند
ALLOWED_HOSTS = ['example.com', 'www.example.com'] # فقط دامنه‌های مجاز

# HTTPS و HSTS
SECURE_SSL_REDIRECT = True # تمام درخواست‌های HTTP به HTTPS ریدایرکت می‌شوند
SECURE_HSTS_SECONDS = 31536000 # یک سال (فقط اگر مطمئن هستید همیشه از HTTPS استفاده می‌کنید)
SECURE_HSTS_INCLUDE_SUBDOMAINS = True

# محافظت کوکی‌ها
SESSION_COOKIE_SECURE = True # کوکی‌ها فقط روی HTTPS ارسال می‌شوند
CSRF_COOKIE_SECURE = True
```

6. محدود کردن دسترسی‌های ادمین (مثال با django-guardian)

**نصب:**
```bash
pip install django-guardian
```

**تعیین دسترسی‌های سطح آبجکت:**
```python
from guardian.shortcuts import assign_perm

اختصاص دسترسی به یک کاربر برای یک آبجکت خاص
assign_perm('change_post', user, post_obj)

بررسی دسترسی در ویو
from guardian.decorators import permission_required

@permission_required('app.change_post', (Post, 'id', 'pk'))
def edit_post(request, pk):
...
```

7. لاگ‌گیری حملات (مثال با django-axes)

**نصب:**
```bash
pip install django-axes
```

**اضافه کردن به settings.py:**
```python
INSTALLED_APPS = [
...
'axes',
]

AUTHENTICATION_BACKENDS = [
'axes.backends.AxesBackend', # باید اول باشد
'django.contrib.auth.backends.ModelBackend',
]

قفل کردن حساب پس از ۵ تلاش ناموفق
AXES_FAILURE_LIMIT = 5
AXES_COOLOFF_TIME = 1 # 1 ساعت قفل شدن
```

---

جمع‌بندی

با این مثال‌ها می‌توانید دقیقاً ببینید که چگونه هر نکته امنیتی را در جنگو پیاده‌سازی کنید. نکته مهم این است که امنیت یک فرآیند مداوم است و همیشه باید کدهای خود را بررسی و به‌روز نگه دارید.

اگر تجربه یا نکته خاصی یا سوالی در این زمینه دارید، خوشحال می‌شوم با من به اشتراک بگذارید!

Back to Blog