stop counting the frontend developer's port numbers

فهرستِ ثابتِ CORS (۳۰۰۰ و ۵۱۷۳) روزی شکست که Vite دید ۵۱۷۳ اشغال است و
بی‌سروصدا رفت روی ۵۱۷۴ — رفتارِ پیش‌فرضِ خودش. فرانت‌کار خطای CORS گرفت، از
سمتِ سرور هیچ ردی در هیچ لاگی نبود (خطا فقط در کنسولِ مرورگر دیده می‌شود)، و
چون هم‌زمان با تغییراتِ بک‌اند شد به اشتباه گردنِ ما افتاد. هزینه‌اش یک ویرایشِ
.env و یک ری‌استارتِ پروداکشن بود، برای چیزی که اصلاً به پروداکشن ربطی نداشت.

به‌جای شمردنِ پورت‌ها، الگوی «هر پورتی روی خودِ ماشینِ توسعه‌دهنده» پذیرفته شد.
سطحِ حمله اضافه نمی‌کند: توکنِ ما در هدر است نه کوکی و CORS_ALLOW_CREDENTIALS
خاموش، پس صفحه‌ای روی localhostِ مهاجم هیچ اعتبارنامه‌ای از مرورگرِ قربانی
نمی‌گیرد؛ CORS هم اصلاً سدِ سرور-به-سرور نیست.

تست‌ها هم پوشش می‌دهند که localhost.evil.com و math.tadrisino2.ir.evil.com
همچنان رد شوند.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-20 12:36:45 +03:30
parent d15a28799a
commit 3156bcbbf3
2 changed files with 65 additions and 2 deletions

View File

@@ -134,10 +134,25 @@ SESSION_COOKIE_HTTPONLY = True
# در کنسولِ مرورگر دیده می‌شود.
CORS_DEFAULT_ORIGINS = [
'https://math.tadrisino2.ir', # فرانتِ مستقر
'http://localhost:3000', 'http://127.0.0.1:3000',
'http://localhost:5173', 'http://127.0.0.1:5173', # Vite/CRA محلی
]
CORS_ALLOWED_ORIGINS = _with_defaults('CORS_ALLOWED_ORIGINS', CORS_DEFAULT_ORIGINS)
# ⚠️ پورتِ سرورِ توسعه را نباید فهرست کرد. فهرستِ ثابتِ قبلی (۳۰۰۰ و ۵۱۷۳) روزی
# شکست که Vite دید ۵۱۷۳ اشغال است و بی‌سروصدا رفت روی ۵۱۷۴ — رفتارِ پیش‌فرضِ
# خودش. آن‌وقت فرانت‌کار خطای CORS گرفت، از سمتِ سرور هیچ ردی در هیچ لاگی
# نبود، و چون هم‌زمان با تغییراتِ ما شد، به اشتباه گردنِ بک‌اند افتاد.
# هر بار که این تکرار شود یعنی یک ویرایشِ .env و یک ری‌استارتِ پروداکشن برای
# چیزی که اصلاً به پروداکشن ربطی ندارد.
#
# پس به‌جای شمردنِ پورت‌ها، الگوی «هر پورتی روی خودِ ماشینِ توسعه‌دهنده» را
# می‌پذیریم. این سطحِ حمله اضافه نمی‌کند: احرازِ هویتِ ما توکنِ Bearer در هدر
# است و `CORS_ALLOW_CREDENTIALS` خاموش، پس صفحه‌ای که روی localhostِ یک مهاجم
# باز است هیچ اعتبارنامه‌ای از مرورگرِ قربانی به دست نمی‌آورد؛ CORS هم اصلاً
# سدِ سرور-به-سرور نیست.
CORS_ALLOWED_ORIGIN_REGEXES = [
r'^http://localhost:\d+$',
r'^http://127\.0\.0\.1:\d+$',
]
CORS_ALLOW_CREDENTIALS = False
# فقط مسیرهای API؛ /admin/ و فایل‌های استاتیک لازم نیست از origin دیگر خوانده شوند.
CORS_URLS_REGEX = r'^/api/.*$'