امنیت rand و mt_rand

میدونید بزرگترین ضعف توابعی مثل mt_rand چیه؟
چرا این توابع برای کارهای امنیتی و رمزنگاری بقدر کافی امن نیستن؟
منظورم از کارهای امنیتی و رمزنگاری این نیست که یه پروژهء خیلی سطح بالا و مختص مسائل امنیتی باشه، منظورم اینه که حتی یک کلید امن ساده هم نمیشه باهاشون تولید کرد!

تمام اینا توابع شبه رندوم هستن، اما همین شبه رندوم ها دو نوع دارن. یکی PRNG (به معنای مولد اعداد شبه تصادفی) و دیگری CSPRNG (به معنای مولد اعداد شبه تصادفی امن از نظر رمزنگاری) . مورد دوم رو میشه در خیلی کاربردهای امنیتی و رمزنگاری هم بکار برد، به شرطی که با یک مقدار تصادفی مناسب seed بشه. درواقع وقتی شما دارید از /dev/urandom استفاده میکنید احتمالش زیاده که دارید خروجی یک CSPRNG رو دریافت میکنید، چون آنتروپی قابل حصول از سیستم در واحد زمان محدوده و بنابراین اگر آنتروپی تازه جمع آوری نشده باشه صرفا از خروجی یک CSPRNG که با آنتروپی اولیه seed شده بوده استفاده میشه.
بعکس /dev/random اینطور نیست و بخاطر همین خوندن ازش ممکنه شما رو بلاک کنه تا وقتی که سیستم آنتروپی لازم رو جمع آوری کنه.

mt_rand از نوع PRNG است. و بنابراین برای کاربردهای رمزنگاری مناسب نیست و تایید نشده و خصوصیات لازم رو نداره. جزییات تخصصیش حالا بماند.
اما گذشته از اینها یک چیزی که خیلی مشهود و مهمه و میخواستم بهش اشاره کنم ضعف اساسی در seed این تابع هست که اگر این قضیه رو بدونیم و درک کنیم در این مورد و خیلی موارد دیگه بینش بسیار مفیدی پیدا میکنیم:

چون مقداری که این تابع بعنوان seed میگیره یک عدد صحیح استاندارد است، که اعداد صحیح روی سخت افزارهای 32 بیتی 32 بیت و روی سخت افزارهای 64 بیتی 64 بیت هستن، بنابراین مقدار seed این تابع حداکثر 2 به توان 32 حالت ممکن داره (یک سیستم 32 بیتی رو فرض کردم برای مثال).
درمورد الگوریتم های PRNG هم میدونی که همیشه با یک seed خاص یک توالی خروجی خاص از اعداد رو تولید میکند. فرضا اگر با عدد 5341 اون رو seed کنیم، اعداد 5 8 120 45 99 300 55 … رو در هربار فراخوانی تولید میکنه. خود این توالی اعداد رندوم بنظر میرسه، یعنی بین اعداد تولید شده رابطهء ریاضی خاصی قابل کشف و بهره برداری وجود نداره (البته این مسئله درمورد PRNG ها لزوما بقدر کافی برقرار نیست؛ در اصل درمورد CSPRNG ها درمورد وجود این خصوصیت حداکثر اطمینان وجود داره) و تا تعداد بسیار زیادی عدد هم الگوی اعداد قبلی تکرار نمیشه. اما با داشتن seed یکسان هر بار دقیقا همون توالی اعداد تولید میشن. بخاطر همین seed محرمانه هست. seed اولیه میتونه از منابع مختلفی مثل همون /dev/urandom تامین بشه (یا شاید یک جایی اصلا برنامه نویس چنین منابعی نداشته باشه و خودش یک مقدار اولیهء محرمانه رو بصورت تصادفی برای تابع مشخص بکنه – هرچند بهتره این با پارامترهای دیگری مثل زمان و PID ترکیب بشه).
ولی داستان ما در اینجا اینه که حتی اگر seed شما یک عدد تصادفی 128 بیتی باشه، mt_rand فقط میتونه از 32 بیت اون استفاده کنه و بنابراین امنیت خروجی اون نهایت درحد 32 بیت خواهد بود که امنیت بسیار بسیار پایینی هست برای مقاصد امنیتی. یعنی شما حساب کن مثلا یک کرکر اگر بتونه در هر ثانیه 1000 مقدار seed رو تست کنه و خروجی mt_rand رو به ازای هرکدام از اونها روی کلید شما تست کنه (از طریق وب – از طریق لوکال که خیلی خیلی سریعتره)، زمان لازم برای موفقیت قطعی طرف میشه:

(2^32)/1000/60/60/24~=50

یعنی در عرض 50 روز کلید شما کرک میشه.
چون در این مدت میتونه تمام اون 2 به توان 32 مقدار مختلف برای seed رو تست کنه.
تازه 1000 درخواست در ثانیه درمورد سرورهای قدرتمند و با استفاده از Botnet ممکنه خیلی افزایش پیدا کنه.

اگر seed این تابع این بازهء کوچک رو نداشت و مثلا کل 128 بیت رو قبول میکرد، اونوقت باوجودی که این تابع برای کاربردهای رمزنگاری نیست اما امنیت خیلی بالاتر بود و نمیشد این حملهء Brute-force ساده رو روش اجرا کرد.

این که گفتم بزرگترین و واضح ترین مشکل اینطور توابع هست، ولی گذشته از این بازهم اشکالاتی مهمی دارن که به همین علت CSPRNG نیستن و نباید برای مقاصد امنیتی و رمزنگاری استفاده بشن.

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

*

شما می‌توانید از این دستورات HTML استفاده کنید: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>