
توی دوره رایگان PHP، هر چیزی که برای حرفهای شدن نیاز داری رو یاد میگیری! از مفاهیم پایه تا پیشرفته، همراه با یه پروژه واقعی برای ساخت یه سایت مثل آپارات.
مشاهده بیشتر
توی این دوره با هم یه وبسایت خبری واقعی رو از صفر میسازیم! از طراحی دیتابیس و احراز هویت تا ساخت API و یه پنل مدیریت حرفهای، همه رو یاد میگیریم و آماده پروژههای واقعی میشی!
مشاهده بیشترمشخصات مقاله
آموزش امنیت در PHP
آموزش امنیت در PHP
اعتبار سنجی داده در PHP
برای دریافت اطلاعات کاربری معمولا از فرم استفاده می کنیم. در این فرم، از انواع کنترل ها استفاده می کنیم. کاربر از این کنترل ها برای وارد کردن داده استفاده می کند. بعد از وارد کردن داده ها کاربر معمولا انرا ارسال می کند. داده ای که کاربر ارسال می کند توسط پارامترهای http انتقال می یابد. کد زیر یک فرم را می سازد:
Simple Form for Age Calculationtitle>
در زیر برنامه محاسبه سن آمده است.
// Listing Program: HitungUmur.php function count_ages($start, $end) { if( $start != '0000-00-00' and $end != '0000-00-00' ) { $timestamp_start = strtotime($start); $timestamp_end = strtotime($end); if( $timestamp_start >= $timestamp_end ) return 0; $start_year = date("Y",$timestamp_start); $end_year = date("Y", $timestamp_end); $num_days_start = date("z",strtotime($start)); $num_days_end = date("z", strtotime($end)); $num_days = 0; $i = 0; if( $end_year > $start_year ) { while( $i < ( $end_year - $start_year ) ) { $num_days = $num_days + date("z", strtotime(($start_year + $i)."-12-31")); $i++; } } return floor((( $num_days_end + $num_days ) - $num_days_start)/360); } else { return 0; } } $born = $year."-".$month."-".$date; $now = date("Y-m-d"); echo count_ages($born,$now); ?>
در محاسبات بالا، برنامه نویس تابعی به نام count_ages() تعریف کرده که محاسبه را انجام می دهد.
اعتبارسنجی عددی در PHP
حالا، فرم را با کد زیر می سازیم:
Order Form Order, Please...font>
حالا کدی می نویسیم تا مقدار کلی که کاربر باید پرداخت کند را حساب کند
// Listing Program: HitungPesanan.php function Calc_Order($price,$order){ return $pay = $price * $order; } echo "Total you must pay: "; echo number_format(Calc_Order(1000,$total),2,",","."); ?>
اگر کاربر مقدار -20 را وارد کند چه می شود؟ مقدار حساب شده منفی می شود. برای حل این مشکل باید مقدار وارد شده را به عدد صحیح Cast کرد و بعد اعتبار سنجی را روی ان انجام داد. برنامه را به این شکل تغییر می دهیم:
// Listing Program: HitungPesanan.php function Calc_Order($price,$order){ $order = (int)$order; if ($order < 1){ return 0; } return $pay = $price * $order; } $total = Calc_Order(1000,$total); if ($total > 0){ echo "You must pay: "; echo number_format(Calc_Order(1000,$total),2,",","."); }else{ echo "Order input not valid"; } ?>
در کد بالا اگر مقدار وارد شده کمتر از یک باشد، سفارش غیر مجاز است. این کار در چند خط از کد که در زیر امده انجام می شود:
if ($order < 1){ return 0; }
ممکن است سوال کنید چرا جلوی متغیر $order از int استفاده کرده ایم. خب. این یک Cast است که مقدار را به عدد صحیح تبدیل می کند. در واقع تمام پارامترهای ارسالی به صورت رشته اند.
مقادیر عددی در PHP
عدد صحیح می تواند به هر چیزی تبدیل شود. مثال زیر را ببینید:
اعتبار سنجی رشته ای در PHP
کاربران برای وارد کردن نام خود، ادرس خود و کد پستی خود از ان استفاده می کنند. خطررشته های اعتبار سنجی نشده چیست؟ ساده ترین نمونه وقتی است که با پایگاه داده ارتباط داریم. در مثال زیر خطر عدم اعتبارسنجی رشته ها را در مثالی توضیح می دهیم.
قبل از ان، پایگاه داده ای به نام phpsecurity بسازید. با پرس و جوس زیر جدولی بسازید:
$a = 1234; # decimal $a = -123; # negative $a = 0123; # oktal (ekivalen 83 desimal) $a = 0x1A; # hexadecimal (ekivalen 26 desimal) ?>
بعد فرمی را برای ورودی داده کاربر اماده می کنیم:
Cek SQL
if ($submit or $uname){ $conn = mysql_connect('localhost','','') or die(mysql_error());
فرم لاگین ی با کد زیر می سازیم:
Login
کد بالا را اجرا و نام کاربری درست را وارد کنید. هنگامی که نام کاربری درست را وارد می کنیم وارد می شود.
حالا برای نام کاربری مقدار زیر را وارد کنید:
نام کاربری: ' or uname != ' and password: ') or password !=('
کاربر با موفقیت وارد سیستم می شود.
به این خاطر با موفقیت لاگین کردید که توانستید از طریق یک کنترل باکس متنی دستور sql را دستکاری کنید:
SELECT count(1) as ada FROM user
WHERE uname='' or uname != '' AND password=md5('')
or password !=('')
برای رفع این آسیب پذیری دو راه وجود دارد:
- محدود کردن نام کاربری و پسورد به حروف و اعداد
- اعتبارسنجی دقیق
راه اول مجبور کردن کاربر به استفاده از نام کاربری و پسورد حرفی و عددی است. یعنی حروف a-z، A-Z و اعداد 0-9. کد زیر راببینید:
if ((ctype_alnum($uname) == false) or (ctype_alnum($pass) == false)){ die("Sorry, you must enter alphanumerik."); }
کد بالا محتوای متغیر های $uname و $pass را برسی می کند تا ببیند حرفی-عددی است یا نه. اگر یکی از این دو نباشد، اسکریپت متوقف می شود.
کد بالا را می توانید در پروسه چک کردن داده در پایگاه داده قرار دهید:
if ($submit or $uname){ if ((ctype_alnum($uname) == false) or (ctype_alnum($pass) == false)){ die("Maaf, Anda harus menginputkan alphanumerik."); } $conn = mysql_connect('localhost','','') or die(mysql_error()); $db = mysql_select_db('phpsecurity'); $sql = "SELECT count(1) as ada FROM user WHERE uname='".$uname."'AND password=md5('".$pass."')"; echo $sql."
"; $q = mysql_query($sql) or die(mysql_error()); $r = mysql_fetch_array($q); $jumlah = $r[ada]; mysql_close(); if ($jumlah > 0){ echo "Success enter"; }else{ echo "Sorry, wrong pair"; } }
راه دوم، اعتبار سنجی دقیقی روی داده های کاربر اعمال می کنید.
ورودی ها در PHP
منابع ورودی معمولا شامل
- Get
- Post
- Cookie
- متغیر های محیطی سرور
- متغیر های محیطی سیستم
معمولا کاربران تازه کار توجهی به منبع ورودی داده نمی کنند. حتی ممکن است تفاوت Get را از Post ندانند. کد زیر راببینید:
ContohGet.php-->if ($kirim){ echo $nama; } ?>
کد بالا را اجرا کنید. فرم را پر و ارسال کنید. حالا نوار ادرس را ببینید. می بینید تمام پارامترها و مقادرشان در نوار ادرس ظاهر شده اند:
http://localhost:8004/PhpSecurity/Bab1/ContohGet.php?nama=Ilmia&kirim=kirim
اگر مقادیر پارامترها به این شکل در نوار ادرس ظاهر شود یعنی ما از Get استفاده کرده ایم. کد زیر از Post استفاده می کند:
ContohPost.php-->if ($kirim){ echo $nama; } ?>
مشکل زمانی رخ می دهد که یک پارامتر از بیش از یک منبع ظاهر شود. مثلا، با استفاده از Post یک id اضافه کرده اید. در طرف دیگر id توسط یک کوکی هم ارسال شده است. PHP
یکی از این دو را انتخاب می کند. کدامیک؟
راه حل را می توان در فایل php.ini دید. این موضوع توسط gpc_order (برای نسخه های قدیمی PHP) و variables_order (برای نسخه های جدید PHP) کنترل می شود. فایل php.ini را باز کنید و خط زیر را بیابید:
; This directive is deprecated.
; Use variables_order instead.
gpc_order = "GPC"
همانطور که می بینید، مقدار پیش فرض gpc_order برابر GPC است که به معنای Get، Post و Cookie است. مقادیر به ترتیب ضعیف ترین تا قویترین هستند. به این ترتیب اولویت اول کوکی است. در نسخه های جدید PHP از variables_order استفاده می شود:
; This directive describes the order in which ; PHP registers GET, POST, Cookie, ; Environment and Built-in variables (G, P, C, E & S ; respectively, often ; referred to as EGPCS or GPC). Registration is done from ; left to right, newer ; values override older values. variables_order = "GPCS"
در کد بالا اولویت اول با system/server است، بعد با کوکی، Post و Get.
برای دسترسی به مقدار یم متغیر در یک دامنه خاص (مانند کوکی، Get) از متغیرهای زیر می توانیم استفاده کنیم:
آپلود فایل در PHP
برخی سایت ها اجازه آپلود کردن فایل ها را به کاربران می دهند. مثلا کاربران می توانند عکس های خود را اپلود کنند.
وقتی کاربر اجازه می یابد فایلی را روی سرور آپلود کند، باید مواظب ان باشید. ساده ترین حالت، کنترل اندازه فایل آپلودی است. تصور کنید عکس ارسالی ممکن است از نوع bmp باشد که اندازه بالایی دارد. میزان فضای ازاد سرور چه قدر است. چند کاربر قرار است فایل اپلود کنند؟
اجازه دهید کدی بنویسیم که کار آپلود را انجام می دهد:
if ($kirim){ $uploaddir = $_SERVER['DOCUMENT_ROOT']."/phpsecurity/bab1/"; $uploadfile = $uploaddir . $_FILES['ufile']['name']; if (move_uploaded_file( $_FILES['ufile']['tmp_name'], $uploadfile)) { echo "Sukses upload"; }else{ print_r($_FILES); } } ?>
با کد بالا می توان هر فایلی با هر اندازه ای را اپلود کرد.
در زیر حجم فایل آپلودی را محدود می کنیم:
if ($kirim){ $uploaddir = $_SERVER['DOCUMENT_ROOT']."/phpsecurity/bab1/"; $uploadfile = $uploaddir.$_FILES['ufile']['name']; $maxsize = 50000; if ($_FILES['ufile']['size'] > $maxsize){ exit("Your file (" . number_format($_FILES['ufile']['size']/1000,0,',','.') . " kb) exceed limit (50kb)."); } if (move_uploaded_file($_FILES['ufile']['tmp_name'], $uploadfile)) { echo "Sukses upload"; }else{ print_r($_FILES); } } ?>
همیشه نمی توان به نوع فایل آپلود شده اطمینان کرد. برای اطمینان از اینکه فایل ارسالی عکس است از کد زیر استفاده می کنیم:
if ($kirim){ $uploaddir = $_SERVER['DOCUMENT_ROOT']."/phpsecurity/bab1/"; $uploadfile = $uploaddir . $_FILES['ufile']['name']; $tipe = $_FILES['ufile']['type']; if ( ($tipe != "image/pjpeg") or $tipe != "image/png") or ($tipe != "image/gif")){ exit("Tipe file Anda: ". $_FILES['ufile']['type'] .". Silakan mengupload file jpeg/png/gif."); } if (move_uploaded_file($_FILES['ufile']['tmp_name'], $uploadfile)) { echo "Sukses upload"; }else{ print_r($_FILES); } } ?>
احراز هویت در (HTTP Authentication) در PHP
حتما به سایت هایی برخورد کرده اید که هنگام باز کردن ان، یک پیغام نمایش داده و از شما نام کاربری و پسورد می خواهد. ماند صفحه اول Cpanel. این صفحات از HTTP Authentication استفاده می کنند.
برای محافظت از صفحه ها با HTTP Authentication، باید دو header را تحویل دهید. WWW-AUTHENTICATE به مرورگر می گوید که به نام کاربری و پسورد نیاز است. header دیگر status است که باید HTTP/1.0 401 Unauthorized باشد. header حالت عادی HTTP/1.0 200 OK است.
مثال. فایلی به نام protectHTTP.php در پوشه www/test/phpsecurity بسازید. کد زیر را وارد کنید:
php // test for username/password if(($_SERVER['PHP_AUTH_USER'] == "mia") AND ($_SERVER['PHP_AUTH_PW'] == "secret")) { echo("successfully!
\n"); } else { //Send headers to cause a browser to request //username and password from user header("WWW-Authenticate: " . "Basic realm=\"PHPEveryDay's Protected Area\""); header("HTTP/1.0 401 Unauthorized"); //Show failure text, which browsers usually //show only after several failed attempts print("This page is protected by HTTP "); } ?>
با مرورگرتان به ادرس http://localhost/test/phpsecurity/protecthttp.php بروید.
اگر مرورگر نام کاربری و پسورد را بفرستد، PHP به طور خودکار دو متغیر PHP_AUTH_USER و PHP_AUTH_PW را در آرایه _SERVER می سازد.
درخواست یک صفحه محافظت شده با HTTP Authentication
در بالا یک صفحه محافظت شده نوشتیم. در اینجا ان صفحه را از درون صفحه ای دیگر باز خواهیم کرد.
php // test for username/password if(($_SERVER['PHP_AUTH_USER'] == "mia") AND ($_SERVER['PHP_AUTH_PW'] == "secret")) { echo("successfully!
\n"); } else { //Send headers to cause a browser to request //username and password from user header("WWW-Authenticate: " . "Basic realm=\"PHPEveryDay's Protected Area\""); header("HTTP/1.0 401 Unauthorized"); //Show failure text, which browsers usually //show only after several failed attempts print("This page is protected by HTTP "); } ?>
در بالا یک صفحه محافظت شده نوشتیم. در اینجا ان صفحه را از درون صفحه ای دیگر باز خواهیم کرد.
php //open socket if(!($fp = fsockopen("localhost", 80))) { print("Couldn't open socket!
\n"); exit; } //make request for document fputs($fp, "HEAD /test/phpsecurity/protecthttp.php HTTP/1.0\r\n"); //send username and password fputs($fp, "Authorization: Basic " .base64_encode("mia:secret") ."\r\n"); //end request fputs($fp, "\r\n"); //dump response from server fpassthru($fp); ?>
در خط 13، نام کاربری و پسورد را اینگونه تغییر دهید:
base64_encode("youyou:secret")
احتمالا پیغامی اینگونه را دریافت می کنید:
HTTP/1.1 401 Unauthorized Date: Wed, 27 Feb 2008 23:43:32
Apache/2.0.59 (Win32) PHP/4.4.7 X-Powered-By:
PHP/4.4.7 WWW-Authenticate: Basic realm="PHPEveryDay's
Protected Area" Connection: close Content-Type: tex
لاگین با استفاده از phpSecureLogin
تازه کارید؟ یا وقت نوشتن کد سیستم لاگین را ندارید؟ کلاسی وجود دارد که کمک می کند سیستم لاگین را راحت بسازیم. این کلاس PhpSecureSite است. به راحتی می توانید انرا در سایتتان به کار ببرید.
PhpSecureSite یک سیستم احراز هویت(authentication) و کنترل کننده جلسه (session-handling) است. PhpSecureSite فقط برای استفاده در صفحات وب نوشته شده است. طوری طراحی شده تا کاملا با برنامه تحت وب مجتمع شود، بنابراین باید برای قسمت نمایش ان (مثلا، صفحه لاگین) خودتان کد بنویسید.
برای درک سیستم کنترل کننده جلسه، باید نگاهی به نحوه کار وب سرور داشته باشیم. پروتکل HTTP، یعنی زبان ارتباطی مرورگر و وب سرور، یک پروتکل به اصطلاح stateless است (وضعیت را نگهداری نمی کند). به این معنا که هنگامی که وب سرور درخواستی برای یک صفحه را دریافت می کند، بدون هیچ سوالی، ان صفحه را بر می گرداند. وب سرور نه می داند و نه علاقه ای دارد بداند چه کسی چه صفحه ای را درخواست داده است. کنترل کننده جلسه مشخص می کند کدام کاربر صفحه را درخواست داده است، اینگونه می توان صفحه را برای هر کاربر به صورت پویا و سلیقه ای ساخت.
به وضوح، استفاده اصلی از PhpSecureSite برای کنترل دسترسی به صفحات وب است، اما موارد استفاده دیگری هم دارد. همراه PhpSecureSite ماژول هایی با قابلیت های دسترسی به متغیر های جلسه (متغیر ها یی که برای جلسه ذخیره و در تمام صفحات قابل دسترسی اند)، دسترسی به لیست کنترل (control list) (برای تعیین دسترسی کاربران به صفحه ها) و موارد دیگر، وجود دارد.
این کلاس را می توانید از ادرس ftp://oss.codepoet.no/phpsecuresite/phpsecuresite-0.1.2.tar.bz2 دانلود کنید.
نصب PhpSecureSite
بعد از آشنایی با PhpSecureSite، نحوه نصب ان را برسی می کنیم. برای این منظور می توانید از پایگاه داده مورد علاقه تان استفاده کنید. مراحل زیر را دنبال کنید:
- PhpSecureSite را از ادرس ftp://oss.codepoet.no/phpsecuresite/phpsecuresite-0.1.2.tar.bz2 دانلود کنید.
- آنرا درون پوشه تست، مثلا www/test/phpsecuresite قرار دهید.
- انرا استخراج کنید، پوشه ای شبیه phpsecuresite-0.1.2 خواهیم داشت.
- برای راحتی انرا به phpsecuresite تغییر نام دهید. باید ساختار فایلی شبیه تصویر داشته باشیم:

- در گام بعد پایگاه داده را اماده می کنیم. پایگاه داده کنونی تان را باز کنید. برای این مثال از پایگاه داده test استفاده می کنیم.
- زبانه import در phpmyadmin را بزنید.

- دستورات روی صفحه را ادامه دهید. در صورت موفقیت باید این صفحه ظاهر شود.

پیکره بندی PhpSecureSite
بعد از نصب PhpSecureSite، باید پیکره بندی ان را انجام دهیم. در PhpSecureSite تعداد زیادی آپشن (گزینه) برای پیکره بندی وجود دارد، در اینجا ما فقط پیکره بندی پایگاه داده و authentication را انجام می دهیم.
پیکره بندی پایگاه داده در PHP
- فایل database.php را از درون www/test/phpsecuresite/phpsecuresite/phpss/config باز کنید.
- در خط احتمالا 36، مطمئن شوید پایگاه داده mysql انتخاب شود.
$phpss_cfg["phpss"]["database_module"] = "mysql";
- سپس، تنظیمات Mysql را اینگونه مشخص کنید:
$phpss_cfg["database"]["mysql"] = array("modulefile" => PHPSS_ROOT_FS . "/modules/database/mysql.php", // database server address (fully-qualified domain name or ip address) "hostname" => "localhost", // tcp port number to connect to //(mysql uses 3306 by default) "port" => 3306, // username and password to connect with "username" => "root", "password" => "secret", // the database to use "database" => "test" );
پیکره بندی authentication
- فایل authentication.php را از درون www/phpsecuresite/phpsecuresite/phpss/config باز کنید. .
- ماژول authentication را مشخص کنید:
$phpss_cfg["phpss"]["auth_module"] = "database";
- فرمت پسورد را مشخص کنید:
$phpss_cfg["phpss"]["auth_pwtype"] = "md5";
مدیریت PhpSecureSite
حالا باید کاربرمان را در پایگاه داده تعریف کنیم. کاربری را به عنوان مدیر (administrator) در پایگاه داده تولید می کنیم:

ساخت فرم لاگین در PHP
در اینجا، 3 فایل می سازیم. form.html برای لاگین، login.php برای اعتبارسنجی و secretpage.php به عنوان یک صفحه محافظت شده.
form.htmlLogin Page
login.php php require ("./phpsecuresite/phpss/phpss.php"); $status = phpss_login($_POST["username"],$_POST["password"]); switch($status){ case "phpss_login_allow": header("location:secretpage.php"); exit(); break; case "phpss_login_authfail": print("Your username or password was wrong!"); break; case "phpss_login_bruteforce_account_lock": print("Locked, you are naughty!"); break; case "phpss_login_bruteforce_iplock": print("Your IP Locked, you are naughty!"); break; default: print("Not Known"); } ?>
secretpage.phpSecret Page Wellcome!
با مرورگرتان ادرس http://localhost/test/phpsecuresite/form.html را باز کنید. نام کاربری اشتباه وارد کنید و login را بزنید.

محافظت از یک صفحه در PHP
در این قسمت صفحه ای را به عنوان محافظت شده مشخص و اجازه دسترسی به ان را به کاربر نمی دهیم. ابتدا باید لاگین کنند سپس اجازه دسترسی به ان را دارند. برای این منظور فایلی می نویسیم که در تمام صفحات محافظت شده، لود می شود.
فایلی با نام global.php بسازید. کد زیر را در ان کپی کنید:
require ("./phpsecuresite/phpss/phpss.php"); function authwrapper(){ $status = phpss_validate(); switch($status){ case "phpss_validate_allow": break; case "phpss_validate_acl_deny": exit("You don't have access right"); break; case "phpss_validate_nosession": exit("Login, Please"); break; case "phpss_validate_hijack_fail": exit("Whats going on your IP?"); break; case "phpss_validate_ipaccess_deny": exit("Your IP blocked"); break; case "phpss_validate_timeout_fail": exit("You session is time out. Relogin, please."); break; default: exit("Sorry!"); } }?>
صفحه محافظت شده را باز کنید. اول صفحه، این کد را وارد کنید:
require "./global.php";
authwrapper();
?>
اگر کاربری بدون لاگین کردن مستقیما به صفحه محافظت شده برود:

صفحه خروج در PHP (Logout)
در انتها باید صفحه ای برای خروج کاربر از سیستم طراحی کنیم. فایلی به نام logout.php ساخته و کد زیر را در ان کپی کنید:
require "./global.php"; authwrapper(); phpss_logout(); header("location:form.html"); ?>