PDA

توجه ! این یک نسخه آرشیو شده می باشد و در این حالت شما عکسی را مشاهده نمی کنید برای مشاهده کامل متن و عکسها بر روی لینک مقابل کلیک کنید : ساخت کد امنیتی در پی.اچ.پی (php) یا همان مبحث ایجاد کپچا (captcha)



Borna66
07-04-2012, 12:02 PM
سلام
در راستای آموزش‌های امنیتی که در زمینه برنامه نویسی به زبان php نوشته بودم امروز در مورد یکی دیگر از موضوعات امنیتی در php می‌خواهم برایتان بنویسم، موضوعی که شاید یکی از مهم‌ترین مبحث ها باشد و جلوی بعضی از حملات و درخواست‌های کاذب را قطعا خواهد گرفت و آن استفاده از کد امنیتی یا همان captcha code می‌باشد.

captcha code چیست؟
حتما شما هم موقع پر کردن فرم ثبت نام و یا سایر فرم‌ها در اینترنت با شکل‌هایی به فرم زیر برخورد داشته اید:

http://pnu-club.com/imported/2012/07/46.jpg


captcha یک کد امنیتی می‌باشد که در ثبت فرم‌ها بر روی اینترنت از آن استفاده خواهند کرد تا انسان را از کامپیوتر و ربت‌های کامپیوتری و یا کرم‌های کامپیوتری تشخیص دهند و اجازه ارسال شدن این فرم‌ها را توسط ربت‌ها ندهد.

چه لزومی به وجود این کد امنیتی می‌باشد؟
خوب فرض کنید فرمی داشته باشیم که در آن از این کد امنیتی استفاده نشده باشد مثلا فرم تماس با ما در سایت‌ها که توسط آن کاربران می‌توانند به ایمیل صاحب سایت میل زده و با آن در ارتباط باشند خوب حالا وقتی این کد امنیتی وجود ندارد اگر مقداری کاربر با زبان‌های سمت سرور و html آشنایی داشته باشد می‌تواند فرمی را طراحی کند با همان فیلد‌ها و مشخصات و به همان آدرسی که فرم سایت ارسال خواهد شد ارسال کند و این عمل ارسال را داخل یک حلقه قرار دهد، خوب حالا چه می‌شود؟؟ بالفرض ما تعداد چرخش این حلقه را بر روی 1000 بگذاریم در این صورت این مشخصات 1000 بار به ایمیل سایت ما ارسال خواهد شد و یا فرم ثبت نام ( به این صورت که نام کاربری برای اینکه تکراری نباشد از شمارنده حلقه در آخر نام کاربری استفاده شود) و ما به این شکل کلی اطلاعات زائد دریافت خواهیم کرد.

خوب حالا که معلوم شد فایده این کد امنیتی چه می‌باشد بریم سراغ ساخت آن.
اول ما کد‌های سمت سرور را نوشته و بعد سراغ ساخت فرم خواهیم رفت.

اول از همه تابع quick_contact_captcha() را خواهیم نوشت که کار آن ساخت تصویر کد امنیتی می‎‌باشد و قسمت اصلی کار هم همین تابع می‌باشد.
بدنه این تابع :


کد:



$chars = "ABCDGHJKMNPRUVWXY346789";
$code = "";
for($i=0;$i<5;$i++) {
$pos = mt_rand(0,strlen($chars)-1);
$code .= $chars{$pos};
}
$_SESSION["quick_contact_captcha"] = $code;




خوب ما اول رشته chars را تعریف می‌کنیم این رشته شامل حروفی می‌باشد که کد امنیتی را تشکیل خواهد داد و حر کاراکتر دلخواهی را که شما بخواهید می‌توانید در آن قرار دهید که اینجا حروف A-Z و اعداد 3-9 در نظر گرفته شده‌اند.
حالا ما متغییر code را تعریف می‌کنیم و به آن مقدار پیش فرض خالی ( empty ) قرار می‌دهیم حال توسط تابع ()mt_rand در php ما یک مقدار یک عدد تصادفی ایجاد می‌کنیم. در تابع ()mt_rand ما دو ورودی قرار میدهیم که بازه عدد رندم را نشان خواهد داد که در اینجا عدد 0 و یکی کمتر از طول رشته chars را به عنوان ورودی‌های آن قرار خواهیم داد حال ما عددی تصادفی خواهیم داشن که آنرا داخل متغییر pos نگهداری می‌کنیم و در خط بعدی خواهیم گفت متغییر شماره pos امین از رشته chars را انتخاب کن و داخل متغییر code نگهداری کن خوب تا به اینجا ما 1 کاراکتر از کد امنیتی خود را ساخته ایم، حال این عمل را داخل یک حلقه با چرخش 5 مرتبه قرار خواهیم داد تا هر بار یک کاراکتر به صورت کاملا تصادفی از رشته داده شده انتخاب شود و هر بار آن را به اخر رشته متغییر code اضافه می‌کنیم. همون طور که میدونید این کار توسط =. صورت می‌گیرد که :


کد:



$code .= $chars{$pos} مساوی با $code = $code.$chars{$pos}




خوب حالا ما کد امنیتی مورد نظر را ایجاد کرده‌ایم و نوبت آن رسیده که آنرا داخل session ای به نام quick_contact_captcha نگهداری نماییم علت استفاده از session هم به خاطر امنیت بالای آن می‌باشد که در آخر آموزش خواهم گفت علت استفاده از session چیست و آیا می‌توان آنرا با cookie عوض کرد یا نه.

تنها وجود این اعداد کافی نمی‌باشد و امنیت را تضمین نمی‌کند چون اگر ما از این اعداد به صورت رشته در صفحه استفاده کنیم ربوت ‌ها قادر خواهند بود که آنرا خوانده و شناسایی نمایند برای همین توسط زبان سمت سرور php آنرا تبدیل به عکس می‌کنیم، پس بهتر خوب به این قسمت دقت نمایید.
اولین قدم تعیین طول و عرض عکس مورد نظر و درخواست دادن ایجاد آن به php است که توسط کد زیر انجام می‌شود:


کد:



$width = 60;
$height = 30;
$image = imagecreate($width, $height);




در اینجا ما درخواست داده ایم که عکسی با ابعاد 60 در 30 ایجاد شود و این کار را توسط تابع ()imagecreate انجام می‌دهیم که طول و عرض عکسی را که قرار است ساخته شود دریافت می‌کند.

حال ما به عکس خودمان رنگ پس زمینه دلخواه خواهیم داد.


کد:



imagefill($image,0,0,imagecolorallocate($image,255 ,255,255));




تابع ()imagefill همان طور که می‌بینید دارای 4 وردی می‌باشد که اولی همان سورس عکس می‌باشد که درخواست ساخته شدنش را دادیم دو پارامتر بعدی مختصات محلی هستش که باشید ایجاد پس زمینه از آنجا شروع شود که آن را 0 و 0 قرار داده ایم یعنی بالا سمت چپ و پارامتر بعدی رنگ پس زمینه را مشخص می‌کند که ما برای ایجاد رنگ از تابع ()imagecolorallocate استفاده کرده ایم که این تابع نیز 4 پارامتر ورودی دارد اولی سورس عکسی که درخواست ساخت آن داده شده است می‌باشد و 3 مقدار بعدی اعدادی از 0 تا 255 می‌باشند که به ترتیب میزان رنگ قرمز، سبز و آبی را مشخص می‌کنند.

توسط کد‌های زیر نیز ما 2 مستطیل و بیضی و 2 خط برای سخت تر خوانده شدن عبارت استفاده می‌کنیم:


کد:


//توابع رسم دو مستطیل

imagefilledrectangle($image,rand(10,50),rand(3,17) ,rand(5,55),rand(5,20),
imagecolorallocate($image,rand(175,255),rand(175,2 55),rand(175,255)));
imagefilledrectangle($image,rand(10,50),rand(3,17) ,rand(5,55),rand(5,20),
imagecolorallocate($image,rand(175,255),rand(175,2 55),rand(175,255)));
//رسم یک بیضی
imageellipse($image,rand(10,50),rand(3,17),rand(5, 55),rand(5,20),
imagecolorallocate($image,rand(175,255),rand(175,2 55),rand(175,255)));
//رسم دو خط در پس زمینه
imageline($image,0,3+rand(0,5),$width,3+rand(0,5),
imagecolorallocate($image,rand(0,255),rand(0,255), rand(0,255)));
imageline($image,0,11+rand(0,5),$width,11+rand(0,5 ),
imagecolorallocate($image,rand(0,255),rand(0,255), rand(0,255)));




با توجه به توضیحاتی که قبلا دادم کاربرو و علکرد این توابع و پارامتر‌هایشان کاملا مشخص و واضح است.

خوب حالا عکس ساخته شد و یکسری خط و خطوط هم بهش اضافه شده تا ربت‌ها نتونن عکس رو اسکن کنند و عبارت داخلش رو تشخیص بدن که چه چیزی هستش چون اگر کد ما داخل یه پس زمینه معمولی بود قابل اسکن شدن توسط ربوت@ها و تشخیص رشته داخلش بود اما با اضافه شدن این اشکال و خط‌ها به پس زمینه این امکان رو هم از بین خواهیم برد.
خوب حالا فقط مونده کدی رو که اول ساختیم رو روی این عکس چاپ کنیم تا جزئی از عکس بشه برای ان کار از کد‌های زیر استفاده می‌کنیم:


کد:



$start = 3;
for($i=0;$i<5;$i++) {
$start += rand(0,3);
imagestring($image,5,$start,rand(2,5),substr($code ,$i,1),
imagecolorallocate($image,rand(0,125),rand(0,125), rand(0,125)));
$start += 9;
}




در خط اول ما متغییری به نام start رو تعریقف می‌کنیم و به ان مقدار پیش فرض 3 را نسبت می‌دهیم که این متغییر مشخصات ایکس را برای نوشتن اولین کاراکتر کد امنیتی روی عکس مشخص می‌کند و بعد دوباره به صورت تصادفی مقداری از 0 تا 3 به متغییر start اضافه میکنیم و حال توسط تابع ()imagestring اولین کاراکتر رو روی عکس چاپ میکنیم که این تابع 5 تا ورودی دارد که اولی سورس عکسی است که درخواست ساخته شدن آن را داده بودیم دومی اندازه فونتی است که قرار است کد امنیتی را روی عکس چاپ کند که مقادیر 1 تا 5 را می‌تواند داشته باشد که هرچی این عدد بیشتر باشد فونت ما درشتر خواهد بود. دو متغییر بعدی هم مختصات x و y ای را که قرار است کاراکتر کد از انجا شروع به رسم شدن کنند مشخص می‌کنند متغییر بعدی کاراکتری را که باید چاپ شود مشخص می‌کند که واضح است چه طور کاراکتر از بین اون 5 کارکتر رشته کد امنیتی انتخاب می‌شود و پارامتر بعدی هم که رنگ کاراکتری را که باید چاپ شود مشخص می‌کند و در آخر به متغییر start مقدار 9 را ضافه می‌کنیم تا کاراکتر بعدی از محل دیگه ای شروع به رسم شدن کند و اینعملیات را داخل یک حلقه 5 مرتبه‌ای قرار میدهیم تا تک تک کاراکتر‌های کد امنیتی چاپ شود حال کد امنیتی ما که به صورت عکس می‌باشد آماده است.
و با توابع زیر هم به عکس مورد نظر کادر میدهیم و در هدر مشخص میکنیم که این یک عکس هستش و با تابع بعدی از عکس مان با پسوند jpg خروجی میگیریم و در نهایت هم سورس عکس ساخته شده را آزاد می‌کنیم:


کد:



imagerectangle($image,0,0,59,19,imagecolorallocate ($image,0,0,0)); //Put Border around image
header("Content-Type: image/jpeg"); //Add JPG Header
imagejpeg($image); //Output the newly created image in jpeg format
imagedestroy($image); //Free up resources




خوب تا حد زیادی کار رو انجام دادیم و کد‌های سمت سرور رو نوشیتیم حال در اول همین صفحه عبارت زیر رو قرار می‌دهیم:


کد:



session_start();



یادتان باشد که اولین خط از کد این صفحه باید این دستور را قرار دهید تا بتوانیم از session ها استفاده نماییم.
حال به سراغ ساخت فرم میرویم.
فیلد‌های مورد نظرتان را بسازید و در انتها این کد را قرار دهید:


کد:


کد امنیتی :

<img src="http://www.yoursite.ir/contact.php?quick_contact_action=get_captcha" alt="captcha" />
<input type="text" name="code" id="code" size="15" maxlength="5" />




توسط فیلد‌های فوق ما 1 تکست باکس و یه عکس توی فرم قرار دادیم برای وارد کردن کد و نشان دادن کد تنها نکته این قسمت هم آدرس عکس هستش که حتما باید این عبارت توی آدرس عکس قرار بگیرد:


کد:



?quick_contact_action=get_captcha



که قبل این هم آدرس سایت + آدرس صفحه‌ای هستش که فرم توش استفاده شده و درخواست داده مشه که عکس ساخته بشه و حال باشید در قسمت ابتدایی این صفحه کد زیر را داخل کد‌های php تان قرار دهید:


کد:



if(@$_REQUEST["quick_contact_action"] == "get_captcha") {
quick_contact_captcha();
}



که با این شرط چک میکنیم اگر در آدرس صفحه در خواست ساخته شدن کد امنیتی داده شده بود تابع quick_contact_captcha اجرا شود و کد ساخته شود و داخل session قرار بگیرو و عکس خروجی نیز تهیه گردد.
خوب حالا ما عکس رو به کاربر نشان میدهیم کاربر کد داخل عکس را داخل تکست باک نوشته و فرم را ارسال میکند و ما موقعی که عکس ساخته شد کد را داخل session نگهداری کردیم و حالا کافی است مقایسه ای انجام دهیم که کد ارسال شده توسط کاربر با عبارت ذخیره شده در session که کد ما می‌بشاد برابر است یا نه که اگر برابر بود فرم ارسال شود و اگر اشتباه بود اخطاری به کاربر بدیم و بگیم مجددا تلاش کند.
که این مقایسه را با شرط زیر انجام می‌دهیم:


کد:



if(strtoupper($_POST['code']) == strtoupper($_SESSION["quick_contact_captcha"]))




برای اینکه کد به کوچک و بزرگ بودن حروف حساس است هر دو کد را به حروف کوچک یا بزرگ تبدیل می‌کنیم که اینجا به حروف بزرگ تبدیل کردیم.

خوب به همین راحتی شما کد امنیتی خود را ساختید و از آن استفاده کردید.
علت استفاده از session هم به این دلیل است که اگر کاربر توسط فرم خارجی اطلاعات را ارسال کند برای ما چون وارد صفحه نشده است پس اصلا session ای ساخته نمی‌شود و کد امنیتی موقع چک شدن همیشه مقدار false را برخواهد گرداند و فرم ارسال نخواهد شد برای همین امنیت آن بسیار بالا می‌باشد.

امیدوارم این آموزش هم برایتان مفید بوده باشد.