نتایج ممیزی امنیتی: چرا احساس شرمندگی کردم
اخیراً یک ممیزی امنیتی روی تمام پروژههای جانبیام انجام دادم. این پروژهها شامل بکاند FastAPI، رباتهای تلگرام، PWA و اپلیکیشنهای Streamlit من میشوند.
فکر میکردم چون با دقت کد مینویسم، کدم امن است. اما اشتباه میکردم.
من این باگهای واقعی در محیط عملیاتی (production) را به اشتراک میگذارم تا به شما کمک کنم از آنها دوری کنید. اینها چکلیستهای تئوری نیستند؛ اینها اشتباهاتی هستند که من واقعاً مرتکب شدهام.
تلهی احراز هویت شرطی کدی نوشتم که قبل از تأیید یک API secret، وجود آن را بررسی میکرد. اگر متغیر محیطی (environment variable) وجود نداشت، مرحله بررسی کلاً نادیده گرفته میشد. این یعنی کل API من برای عموم باز بود. قانون: اگر یک secret وجود ندارد، با خطای 500 به شدت متوقف شوید (fail hard). هرگز احراز هویت را نادیده نگیرید.
نشت در تاریخچه Git یک بار برای یک تست سریع، یک API key را به صورت hardcoded نوشتم. بعداً آن را به یک فایل
.envمنتقل کردم و فکر کردم مشکل حل شده است. اما Git همه چیز را به خاطر میسپارد. هر کسی میتواند آن کلید را در تاریخچه کامیتهای (commit history) من پیدا کند. قانون: اگر کلیدی را کامیت کردید، فرض کنید سرقت شده است. بلافاصله آن را تغییر دهید (rotate). ازgit-filter-repoبرای پاکسازی تاریخچه خود استفاده کنید.نشت نقطه انتهایی (endpoint) دیباگ یک endpoint به نام
/debug/configرا در محیط عملیاتی باقی گذاشتم تا به عیبیابی کمک کند. این کار باعث شد URLهای دیتابیس و تنظیمات محیطی من لو برود. قانون: تمام endpointهای دیباگ را قبل از استقرار (deployment) حذف کنید. به جای آن از لاگها استفاده کنید.نشت اطلاعات سیستم از طریق خطاها من در پاسخهای خطای خود از
str(e)استفاده میکردم. این کار باعث میشد خطاهای دیتابیس و مسیر فایلها مستقیماً برای کاربر ارسال شود. مهاجمان از این طریق برای نقشهبرداری از زیرساخت شما استفاده میکنند. قانون: خطای دقیق را برای خودتان لاگ کنید. یک پیام عمومی مثل "Internal Server Error" به کلاینت ارسال کنید.ریسک XSS در فرانتاند من برای رندر کردن محتوای کاربر از
innerHTMLاستفاده میکردم. این کار اجازه میداد اسکریپتها در مرورگر سایر کاربران اجرا شوند. قانون: همیشه HTML را escape کنید. باinnerHTMLمانند روشی برای اجرای کدهای دلخواه برخورد کنید.نبود محدودیت نرخ درخواست (Rate Limits) من endpointهایی داشتم که بدون هیچ محدودیتی مدلهای گرانقیمت هوش مصنوعی را فراخوانی میکردند. یک حلقه ساده یا یک کلید سرقت شده میتوانست صدها دلار برای من هزینه داشته باشد. قانون: احراز هویت جلوی کاربران غیرمجاز را میگیرد. محدودیت نرخ درخواست (Rate limiting) جلوی سوءاستفاده کاربران مجاز از سیستم شما را میگیرد.
سیاست CORS بیش از حد باز (Permissive) من در محیط عملیاتی از
allow_origins=["*"]استفاده کردم. این کار به هر سایتی اجازه میدهد به API شما درخواست ارسال کند. قانون: فقط دامنه فرانتاند خاص خودتان را مجاز بدانید.نشت فایلهای موقت اگر کد من هنگام پردازش یک فایل کرش میکرد، فایل موقت برای همیشه روی دیسک باقی میماند. این کار باعث هدر رفتن فضا و نشت دادههای حساس میشود. قانون: از بلوکهای
try-finallyاستفاده کنید تا مطمئن شوید حتی در صورت بروز خطا، فایلها حذف میشوند.
چکلیست اجباری جدید من:
قبل از کدنویسی:
• ایجاد یک .gitignore
• ایجاد یک .env.example
برای هر endpoint: • افزودن احراز هویت • استفاده از پیامهای خطای عمومی • افزودن محدودیت نرخ (rate limits) به وظایف سنگین
قبل از commit کردن: • اسکن کردن diff برای یافتن اطلاعات حساس (secrets)
قبل از استقرار (deploying): • انجام ممیزیهای امنیتی روی وابستگیها (dependencies)
مشکلات امنیتی تصادفی رخ نمیدهند. آنها به دلیل کامنتهای "TODO" و اصلاحات "موقت" که برای همیشه در محیط عملیاتی (production) باقی میمانند، اتفاق میافتند.
رفع یک باگ خستهکننده است. رفع یک رخنه امنیتی پرهزینه است.