PDA

View Full Version : امنیت rand و mt_rand



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

MostafaEs3
یک شنبه 28 اسفند 1390, 00:34 صبح
چرا میشه دیگه ! باید اول با توابع دیگه کلمه رو تولید کنی . بطور مثال :



<?php
function randomAlphaNum($amount){
$numchars = $amount;
$chars = explode(',','a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s ,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R ,S,T,U,V,W,X,Y,Z,0,1,2,3,4,5,6,7,8,9');
$random='';
for($i=0; $i<$numchars;$i++) {
$random.=$chars[rand(0,count($chars)-1)];
}
return $random;
}
echo randomAlphaNum(32);
echo "<br />".randomAlphaNum(100);
?>


یا مثلا این :



<?php

function RandomString($len){
$randstr = '';
srand((double)microtime()*1000000);
for($i=0;$i<$len;$i++){
$n = rand(48,120);
while (($n >= 58 && $n <= 64) || ($n >= 91 && $n <= 96)){
$n = rand(48,120);
}
$randstr .= chr($n);
}
return $randstr;
}

?>

farhadfery
یک شنبه 28 اسفند 1390, 08:47 صبح
میدونید بزرگترین ضعف توابعی مثل mt_rand چیه؟
چرا این توابع برای کارهای امنیتی و رمزنگاری بقدر کافی امن نیستن؟
منظورم از کارهای امنیتی و رمزنگاری این نیست که یه پروژهء خیلی سطح بالا و مختص مسائل امنیتی باشه، منظورم اینه که حتی یک کلید امن ساده هم نمیشه باهاشون تولید کرد!
اولا بازگشت شما را تبریک می گم. خوشحال دوباره فعالیت خودتون را شروع کردید. فکر می کنم خودتون جوابش را می دونید. اما می خواهید سایر نظرها را هم بدونید.
من اینرا پیدا کردم (http://fa.wikipedia.org/wiki/%D8%AA%D9%88%D9%84%DB%8C%D8%AF_%D8%A7%D8%B9%D8%AF% D8%A7%D8%AF_%D8%AA%D8%B5%D8%A7%D8%AF%D9%81%DB%8C) ه می گه : عداد تصادفی تولید شده توسط رایانه و محاسبات ریاضی اعداد کاملاً تصادفی نبوده و از اینرو این اعداد را اعداد شبه تصادفی (http://fa.wikipedia.org/w/index.php?title=%D8%A7%D8%B9%D8%AF%D8%A7%D8%AF_%D8 %B4%D8%A8%D9%87_%D8%AA%D8%B5%D8%A7%D8%AF%D9%81%DB% 8C&action=edit&redlink=1&preload=%D8%A7%D9%84%DA%AF%D9%88:%D8%A7%DB%8C%D8%A C%D8%A7%D8%AF+%D9%85%D9%82%D8%A7%D9%84%D9%87/%D8%A7%D8%B3%D8%AA%D8%AE%D9%88%D8%A7%D9%86%E2%80%8 C%D8%A8%D9%86%D8%AF%DB%8C&editintro=%D8%A7%D9%84%DA%AF%D9%88:%D8%A7%DB%8C%D8 %AC%D8%A7%D8%AF+%D9%85%D9%82%D8%A7%D9%84%D9%87/%D8%A7%D8%AF%DB%8C%D8%AA%E2%80%8C%D9%86%D9%88%D8%A A%DB%8C%D8%B3&summary=%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF+%DB%8C%DA%A 9+%D9%85%D9%82%D8%A7%D9%84%D9%87+%D9%86%D9%88+%D8% A7%D8%B2+%D8%B7%D8%B1%DB%8C%D9%82+%D8%A7%DB%8C%D8% AC%D8%A7%D8%AF%DA%AF%D8%B1&nosummary=&prefix=&minor=&create=%D8%AF%D8%B1%D8%B3%D8%AA+%DA%A9%D8%B1%D8%AF %D9%86+%D9%85%D9%82%D8%A7%D9%84%D9%87+%D8%AC%D8%AF %DB%8C%D8%AF) می‌نامند.

eshpilen
یک شنبه 28 اسفند 1390, 09:51 صبح
فکر کنم این دو تابع یک random واقعی نیست و در واقع یک شبه رندم هست

و میشه گفت تقریبا قابل حدث زدن. از یک سری چیزها مثل زمان و شماره پروسس استفاده می کنه.
این درسته. ولی خرابی موضوع درمورد توابعی مثل 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 نیستن و نباید برای مقاصد امنیتی و رمزنگاری استفاده بشن.


من قبلا یه همچین چیزی دیدم که روی یه تصویر نشون داده جرا mt_rand و rand یه random واقعی نیست
http://boallen.com/random-numbers.html
البته اونطورکه نوشته اون تست برای rand بوده و اونم فقط روی ویندوز.
روی لینوکس یا درمورد mt_rand چیز خاصی نشون نمیده.


یک سری سرویس هستن مثل random.org که می تونین مقادیر رندم رو به صورت یک سرویس ازش بخوایینآره اینو و یکی دیگه رو دیروز پیدا کردم و داشتم مطالعه میکردم. random.org از نویز اتمسفری برای تولید اعداد رندوم استفاده میکنه که ظاهرا با استفاده از یک گیرندهء امواج رادیویی این نویز رو جمع آوری میکنه (البته بعدش کلی عملیات دیگه هم باید روی نویز جمع آوری شده به این روش انجام بشه تا برای استفاده در مصارف امنیتی مناسب باشه و الگوی کاملا رندوم داشته باشه). یکی دیگه هم بود که از واپاشی رادیواکتیو استفاده میکرد: http://www.fourmilab.ch/hotbits/

مشکل/محدودیت اینا چندتاست.
یکی اینکه حجم اعداد رندوم که در واحد زمان یا به ازای اکانت تحویل میدن زیاد نیست و ممکنه حداقل بعضی جاها یا در بعضی شرایط به محدودیت برخورد کنیم.
دیگر اینکه سرعتشون ممکنه بعضی وقتا پایین باشه. گذشته از اینکه بطور کلی چون پشت صحنه درخواست HTTP یا HTTPS ارسال میشه سرعت بطور متوسط هم پایین میاد.
البته برای رفع این مشکل بنظرم بتونیم پیشاپیش یکسری اعداد رندوم رو دریافت و برای استفاده بعدی ذخیره کنیم (در دیتابیس یا فایل).
بعدهم بهرحال برنامه و سایت به یک سرویس خارجی وابسته میشه و این خودش چندان جالب نیست و دردسرها و عوارض خودش رو داره به علتهای مختلف. منکه شخصا خوشم نمیاد از این کار.
بعد تازه مسائل امنیتی و امکان سوء استفاده توسط همین سرویسها هم خودش در بحث امنیت و رمزنگاری یک مشکل و امتیاز منفی محسوب میشه.
بعد تازه شما باید حتی الامکان از HTTPS استفاده کنید برای گرفتن اعداد رندوم از این سرویسها، چون اینم از نظر امنیتی خودش یک امتیاز منفی دیگر هست که چنین اطلاعاتی که پایهء امنیت هستن از طریق کانال های ناامن و عمومی اینترنت بدون رمزگذاری منتقل بشن. بنابراین باید امکانات استفاده از HTTPS رو روی هاست خودتون داشته باشید، گذشته از اینکه HTTPS خودش کندتر از HTTP است و منابع بیشتری مصرف میکنه.

ولی درکل بعضی جاها شاید چارهء دیگری نباشه جز استفاده از اینطور سرویسها. بنظر من بهتره در این موارد یکسری منابع خودمون رو هم با دیتای رندوم این سرویسها ترکیب کنیم تا امنیت ما درمقابل وابستگی به منابع خارجی بالاتر بره.

eshpilen
یک شنبه 28 اسفند 1390, 10:14 صبح
اولا بازگشت شما را تبریک می گم. خوشحال دوباره فعالیت خودتون را شروع کردید. فکر می کنم خودتون جوابش را می دونید. اما می خواهید سایر نظرها را هم بدونید.

جایی نرفته بودم.
مدتیه دارم روی یک پروژهء رجیستر و لاگین کار میکنم که طبیعتا امنیت درش اساسیه و اولویت بالایی بهش دادم. البته این پروژه بیسش قدیمی بوده و دارم کامل تر و اصولی تر و امن تر میکنمش.
بخاطر همین هم به یک منبع اعداد تصادفی بقدر کافی امن نیاز دارم و دارم روش تحقیق میکنم. چون در چنین پروژه ای به کلیدهای رندوم متعددی نیاز هست که اساس امنیت روی اونها استواره (کلید ایمیل فعال سازی، کلید ریست کردن پسورد، کلید لاگین خودکار و غیره).

باید بگم واقعا تعجب کردم که هنوز در وب برای چنین چیزی راهکار سرراست و همه جایی وجود نداره. و میشه گفت به همین خاطر امنیت خیلی از نرم افزارها و سایتها خدشه داره.
قبلا به اشتباه فکر میکردم طبیعتا توابعی مثل mt_rand باید بقدر کافی امن باشن، چون در PHP اصلا تابع دیگری در دسترس نداریم برای تولید اعداد تصادفی.


من اینرا پیدا کردم (http://fa.wikipedia.org/wiki/%D8%AA%D9%88%D9%84%DB%8C%D8%AF_%D8%A7%D8%B9%D8%AF% D8%A7%D8%AF_%D8%AA%D8%B5%D8%A7%D8%AF%D9%81%DB%8C) ه می گه : عداد تصادفی تولید شده توسط رایانه و محاسبات ریاضی اعداد کاملاً تصادفی نبوده و از اینرو این اعداد را اعداد شبه تصادفی (http://fa.wikipedia.org/w/index.php?title=%D8%A7%D8%B9%D8%AF%D8%A7%D8%AF_%D8 %B4%D8%A8%D9%87_%D8%AA%D8%B5%D8%A7%D8%AF%D9%81%DB% 8C&action=edit&redlink=1&preload=%D8%A7%D9%84%DA%AF%D9%88:%D8%A7%DB%8C%D8%A C%D8%A7%D8%AF+%D9%85%D9%82%D8%A7%D9%84%D9%87/%D8%A7%D8%B3%D8%AA%D8%AE%D9%88%D8%A7%D9%86%E2%80%8 C%D8%A8%D9%86%D8%AF%DB%8C&editintro=%D8%A7%D9%84%DA%AF%D9%88:%D8%A7%DB%8C%D8 %AC%D8%A7%D8%AF+%D9%85%D9%82%D8%A7%D9%84%D9%87/%D8%A7%D8%AF%DB%8C%D8%AA%E2%80%8C%D9%86%D9%88%D8%A A%DB%8C%D8%B3&summary=%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF+%DB%8C%DA%A 9+%D9%85%D9%82%D8%A7%D9%84%D9%87+%D9%86%D9%88+%D8% A7%D8%B2+%D8%B7%D8%B1%DB%8C%D9%82+%D8%A7%DB%8C%D8% AC%D8%A7%D8%AF%DA%AF%D8%B1&nosummary=&prefix=&minor=&create=%D8%AF%D8%B1%D8%B3%D8%AA+%DA%A9%D8%B1%D8%AF %D9%86+%D9%85%D9%82%D8%A7%D9%84%D9%87+%D8%AC%D8%AF %DB%8C%D8%AF) می‌نامند.
درسته.
البته منابعی مثل /dev/random یا /dev/urandom در لینوکس (در ویندوز هم ظاهرا توابعی هست که خواص مشابهی دارن)، درواقع اعداد تصادفی تاحدی واقعی تولید میکنن. بطور مثال با استفاده از نویز و پارامترهای کم و بیش تصادفی در یکسری سخت افزارهای جانبی و دیسک و غیره. البته تاجاییکه میدونم؛ جزییات بیشتری ازش نخوندم؛ اگر منبع خوبی در این ارتباط پیدا کردید مطرح کنید.

اما اعداد رندومی که صرفا توسط توابع و سیستمهای ساده تر تولید میشن کاملا شبه تصادفی هستن و برای خیلی از کاربردهای امنیتی و رمزنگاری مناسب نیستن. نمونش rand و mt_rand و توابع مشابه در خیلی زبانها و کتابخانه ها و فریمورک های برنامه نویسی.

یکسری مولد اعداد رندوم سخت افزاری (http://en.wikipedia.org/wiki/TRNG) هم داریم که اعداد رندومی که کم و بیش واقعی هستن تولید میکنن. کیفیت و امنیتشون به منبع و روش استفاده شده بستگی داره. بعضی هاشون بصورت چیپ و بورد هستن و نیازی به تشکیلات خارجی خاصی ندارن. اما اونایی که از منابع خارجی مثل فروپاشی رادیواکتیو یا نویز اتمسفری استفاده میکنن احتمالا امنیت بیشتری دارن.
سرعت تولید اعداد تصادفی واقعی توسط این روشهای سخت افزاری معمولا خیلی کمتر از روشهای نرم افزاری تولید اعداد شبه تصادفی است. گذشته از اینکه به تجهیزات و روشهای خاص و پیچیده تر و هزینهء خودشون نیاز دارن (هرچند این هزینه درمورد انواع ساده بصورت چیپ و بورد ممکنه زیاد نباشه).

farhadfery
یک شنبه 28 اسفند 1390, 10:22 صبح
احتمالا سایت های هستند که کد رندوم مناسب و به قول شما کم و بیش واقعی را از آنها درخواست کنید و به شما بدهند. اما تا اونجا که از شما شناخت پیدا کردم, احتمالا شما با دریافت کد از بیرون و تولید آن توسط دیگران راضی نباشید.

این هم یه لینک که کارش فروش این قطعات. مولد اعداد رندوم
http://comscire.com/Home/


ما اونایی که از منابع خارجی مثل فروپاشی رادیواکتیو یا نویز اتمسفری استفاده میکنن احتمالا امنیت بیشتری دارن

سایتی سراغ دارید که اعداد رندوم را بر این اساس به ما بده؟

eshpilen
یک شنبه 28 اسفند 1390, 10:28 صبح
احتمالا سایت های هستند که کد رندوم مناسب و به قول شما کم و بیش واقعی را از آنها درخواست کنید و به شما بدهند. اما تا اونجا که از شما شناخت پیدا کردم, احتمالا شما با دریافت کد از بیرون و تولید آن توسط دیگران راضی نباشید.
مسئله از نظر بنده منطقی و فنی و علمیه، ارتباطی به سلیقه و شخصیت نداره.
معایب این سرویسها رو در دو پست بالاتر ذکر کردم.
اما بهرحال گفتم که در بعضی شرایط شاید چاره ای جز استفاده از این سرویسها نباشه. در ضمن بنظرم اگر دیتای رندوم این سرویسها رو با منابع خودمون ترکیب کنیم امنیت بالاتر میره.
بهرحال منابعی مثل /dev/urandom در لینوکس هم هست که بنظر میرسه امنیت قابل توجهی داشته باشن و شاید در کاربردهای عادی ما کفایت کنه. روی VPS ها که حتما دسترسی بهش مشکلی نداره، ولی اگر روی شیرهاست مشکل دسترسی بود ادمین سرور میتونه این دسترسی رو بده (باید آدرس این فایل رو در open_basedir اضافه کنه).

سایتی سراغ دارید که اعداد رندوم را بر این اساس به ما بده؟
پستهای بالا رو کامل و دقیق بخونید. مطالب بسیار جالب و مفیدی درشون هست. شونصدتا منبع رو باید مدتها بخونی تا بتونی چنین درک و خلاصه ای بدست بیاری.
آدرس دوتا از این سایتها هم در مطالب آمده.

eshpilen
یک شنبه 28 اسفند 1390, 11:13 صبح
چرا میشه دیگه ! باید اول با توابع دیگه کلمه رو تولید کنی . بطور مثال :



<?php
function randomAlphaNum($amount){
$numchars = $amount;
$chars = explode(',','a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s ,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R ,S,T,U,V,W,X,Y,Z,0,1,2,3,4,5,6,7,8,9');
$random='';
for($i=0; $i<$numchars;$i++) {
$random.=$chars[rand(0,count($chars)-1)];
}
return $random;
}
echo randomAlphaNum(32);
echo "<br />".randomAlphaNum(100);
?>


یا مثلا این :



<?php

function RandomString($len){
$randstr = '';
srand((double)microtime()*1000000);
for($i=0;$i<$len;$i++){
$n = rand(48,120);
while (($n >= 58 && $n <= 64) || ($n >= 91 && $n <= 96)){
$n = rand(48,120);
}
$randstr .= chr($n);
}
return $randstr;
}

?>

امنیت اینطور روشها اساسا بر مبنای امنیت اعداد رندوم تولید شده توسط توابعی مثل rand و mt_rand استوار است و بنابراین امنیت در کل بیش از حد پایین است. گذشته از محدودیت seed که در بدترین حالت 2 به توان 32 مقدار ممکن و در بهترین حالت 2 به توان 64 مقدار ممکن دارد (شاید 2 به توان 64 برای خیلی کاربردها یا سایتها در عمل مشکلی ایجاد نکند، اما از نظر اصول علم رمزنگاری و امنیت صحیح نیست و بنابراین اثبات و تضمینی وجود ندارد)، استفاده از منابعی مثل زمان بجای استفاده از یک seed که منبع تصادفی واقعی تری داشته باشه، امنیت را تا حد زیادی پایین میاورد.
بطور مثال خیلی وقتها یک محدودهء زمان انجام عملیات برای هکر مشخص است. بطور مثال وقتی هکر خودش درخواست HTTP را داده باشد، یا وقتی از طریق خاصی به زمان درخواست کاربر با تقریب کافی دست پیدا کرده باشد (سناریوهای زیادی ممکن هستند).
بنابراین محدوده زمانهای ممکن بکار رفته در seed تاحد چشمگیری کوچک میشوند.

بنظرم اگر PID را هم به این فرایند اضافه کنید بسیار بهتر خواهد بود.
البته طرز ترکیب اینها خودش احتمالا داستان و اصول دارد.
بطور مثال در کد منبع PHP برای seed خودکار mt_rand از این روش استفاده شده است:

mt_srand(fmod(time() * getmypid(), 0x7FFFFFFF) ^ fmod(1000000 * lcg_value(), 0x7FFFFFFF));

بنظر بنده اصولا باید از یک شکل دیگری استفاده کرد. و همچین یک منبع seed مناسبتر در صورت امکان.