سلام
در راستای آموزش*های امنیتی که در زمینه برنامه نویسی به زبان php نوشته بودم امروز در مورد یکی دیگر از موضوعات امنیتی در php می*خواهم برایتان بنویسم، موضوعی که شاید یکی از مهم*ترین مبحث ها باشد و جلوی بعضی از حملات و درخواست*های کاذب را قطعا خواهد گرفت و آن استفاده از کد امنیتی یا همان captcha code می*باشد.

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


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

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

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

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

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


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

[PHP]$code .= $chars{$pos}   مساوی با    $code = $code.$chars{$pos}[/PHP]


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

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

[PHP]   $width = 60;    
$height = 30;
$image = imagecreate($width, $height);[/PHP]


در اینجا ما درخواست داده ایم که عکسی با ابعاد 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 را برخواهد گرداند و فرم ارسال نخواهد شد برای همین امنیت آن بسیار بالا می*باشد.