امنیت نرمافزار: ریسکهایی که واقعاً پیش میآیند

امنیت در بیشتر پروژهها بهشکل یک مرحله در انتها دیده میشود: قبل از تحویل، یک تست نفوذ. مشکل این است که چیزهایی که آن تست پیدا میکند، معمولاً تصمیمهای معماریاند و اصلاحشان در آن مرحله گران است.
و نکتهٔ دوم: بیشتر رخنهها از حملهٔ پیچیده نمیآیند. از همان چند اشتباه همیشگی میآیند.
دسترسی، شایعترین و پرهزینهترین
بیش از هر چیز دیگری، مشکل این است که کاربر به چیزی دسترسی پیدا میکند که نباید.
شکل رایجش ساده است: آدرس /orders/1042 را باز میکنید و سفارش خودتان را
میبینید. عدد را به 1043 تغییر میدهید و سفارش یک نفر دیگر را میبینید. سامانه
هویت شما را بررسی کرده — که وارد شدهاید — ولی نپرسیده که آیا این رکورد مال
شماست.
قاعده: بررسی دسترسی باید در سرور و بهازای هر رکورد انجام شود، نه با پنهانکردن دکمه در رابط کاربری. اگر منویی را از دید کاربر حذف کردهاید ولی مسیرش هنوز جواب میدهد، کاری نکردهاید.
و همین قاعده باید در جستجو، API و خروجی اکسل هم اعمال شود. در پیادهسازیها معمولاً صفحهٔ اصلی درست فیلتر میشود و یکی از این سه جا میماند.
ورودی کاربر
تزریق. ورودی کاربر که بهعنوان دستور اجرا میشود. راهش سی سال است شناخته شده: کوئری پارامتری. هرگز رشتهٔ کوئری را با چسباندن ورودی کاربر نسازید. همین یک قاعده، این دستهٔ کامل را میبندد.
اسکریپت در صفحه. ورودی کاربر که بهعنوان کد در مرورگر دیگران اجرا میشود. راهش این است که هنگام نمایش، خروجی را برای همان زمینه کدگذاری کنید. فریمورکهای امروزی این را پیشفرض انجام میدهند مگر جایی که آگاهانه دورش زده باشید — و آن جاها را باید بشمارید و بازبینی کنید.
آپلود فایل. فایلی که کاربر میفرستد و سرور اجرا میکند. فایلها را بیرون از مسیر قابل اجرا ذخیره کنید، نوعشان را از محتوا بررسی کنید نه از پسوند، و نامشان را خودتان تولید کنید.
احراز هویت
رمزها را با الگوریتم مخصوص رمز درهم کنید، نه با درهمساز عمومی. محدودیت نرخ روی تلاش ورود بگذارید. و فراموشی رمز را جدی بگیرید — این مسیر معمولاً کمتر از خود ورود بازبینی میشود و در عمل همان اثر را دارد.
برای سامانهٔ سازمانی، ورود دومرحلهای برای نقشهای مدیریتی حداقل چیزی است که انتظار میرود. جزئیات بیشتر در احراز هویت و ورود یکپارچه.
پیکربندی و وابستگیها
پیشفرضها. رمز پیشفرض که عوض نشده، پنل مدیریتی که روی اینترنت باز است، پیام خطای مفصل که ساختار پایگاه داده را نشان میدهد. اینها آسیبپذیری کد نیستند و بیشتر از خیلی آسیبپذیریهای کد به رخنه ختم میشوند.
کتابخانههای قدیمی. بخش بزرگی از کد شما را دیگران نوشتهاند. کتابخانهای با آسیبپذیری شناختهشده، در دسترس هر کسی است که فهرست وابستگیهای شما را ببیند. بررسی خودکار وابستگیها را در خط لولهٔ ساخت بگذارید؛ کار یک روز است و مداوم جواب میدهد.
اسرار در کد. کلید API و رمز پایگاه داده که در مخزن نشستهاند. اگر یک بار commit شده باشند، در تاریخچه میمانند حتی اگر بعداً حذفشان کنید — و باید عوض شوند، نه فقط پاک.
و آنچه بعد از رخنه اهمیت دارد
اگر اتفاقی افتاد، باید بتوانید بگویید چه شد. یعنی لاگ ورود، لاگ تغییرات حساس، و تاریخچهٔ دسترسیها.
سامانهای که نمیتواند بگوید چه کسی چه چیزی را کی عوض کرد، نمیتواند بگوید رخنهای رخ داده یا نه — که از نظر عملی یعنی فرض کنید رخ داده. ساختارش در پایش و لاگ.
چه چیزی در هر پروژه باید باشد
فهرست کوتاهی که ما در پروژهها اجرا میکنیم و هزینهاش در برابر ریسکش ناچیز است:
بررسی دسترسی بهازای هر رکورد، در سرور.
کوئری پارامتری، همهجا و بدون استثنا.
بررسی خودکار وابستگیها در خط لولهٔ ساخت.
اسرار بیرون از مخزن.
HTTPS اجباری و هدرهای امنیتی پایه.
لاگ رویدادهای حساس.
و بازبینی متمرکز روی نقاطی که ورودی کاربر به کوئری، فایل یا دستور سیستمی میرسد.
زمانبندی
تست نفوذ در انتها را حذف نکنید، ولی تنها اقدامتان نباشد. چیزی که بیشترین بازده را دارد، بازبینی معماری در ابتداست: مدل دسترسی، جریان احراز هویت، و اینکه دادهٔ حساس کجا ذخیره میشود.
آنچه در آن جلسه پیدا میشود، اگر در انتها پیدا میشد، بازنویسی بود.