یک وبلاگ دیگر از یک برنامه نویس دیگر
بایگانی برای سپتامبر, 2010
HTTP Redirect
شهریور ۲۸م
یه چند وقتی هست که مدام درگیر کارهای امنیتی، خصوصا برای PHP هستم. این دفعه میخوام یه مشکل کوچیک رو توضیح بدم. خیلی ها معمولا اینکار رو انجام میدن (دست کم کدی که من امروز دیدم اینطوری بود! ) :
<?php
if (!check_current_user_has_privilege_to_this_page()){
header("Location: some_other_page.php");
}
//
echo "This is very important data!";
این کد، بررسی میکنه یه تابع دسترسی به این صفحه رو داره، اگر نه پاسش میده به یه صفحه دیگه، در غیر اینصورت (یعنی اگه کاربر دسترسی داشت) اطلاعاتی رو که باید نشون بده نشون میده، یا کارهایی که باید انجام بشه رو انجام میده. اطلاعات و یا کارهایی که ما نمیخوایم کاربر عادی بدون رد کردن شرطهای امنیتی مثل رمز ببینه.
ولی اینجا یه مشکل هست :) خیلی هم بزرگه. header() اطلاعات رو میفرسته به طرف کاربر و در طرف کاربر عمل جابجایی (redirect ) انجام میشه. حالا اگه با یه برنامه که درکی از Redirect و اصولا پروتکل HTTP نداره این صفحه باز بشه؟؟ یا بدتر، اول این افزونه فایرفاکس رو نصب کنید بعد صفحه رو باز کنید، البته قبلش آدرس صفحه رو توی تنظیمات افزون اضافه کنید، اینجوری:
میبینید که صفحه کاملا باز میشه.برای مثال آدرس
http://cyberrabbits.net/non/bigbang/headercheck.php
رو چک کنید که این مشکل رو داره، کدش هم اینه :
<?php
/*
* this is an example for redirect problem :)
* */
if (true)
header("Location: http://google.com");
echo "This is very important data, you can not see this!(or you can :) )";
قاعدتا فسمت echo هیچوقت نباید نمایش داده بشه، ولی اون افزونه نصب و فعال باشه دیده میشه :) این یعنی که این روش یه چیزی کم داره.
خوب چاره چیه؟؟
خیلی ساده :
<?php
if (!check_current_user_has_privilege_to_this_page()){
header("Location: some_other_page.php");
die(); //Very sweet :) little , beautiful function!!
}
//
echo "This is very important data!";
یه نکته کوچک در PHP
شهریور ۲۵م
همونطور که میدونید توی PHP برای اپراتور OR دو نسخه وجود داره، وشاید کمتر کسی بدون که اینها دوتا از لحاظ طرز عمل تفاوتی ندارن، ولی اولویت عملیاتی متفاوتی دارن .(چند وقت پیش یه بحثی توی فروم iranphp.org مطرح شد در اینباره.)
به عبارتی خیلیها درست نمیتونن نتیجه این کد رو حدس بزنن :
<?php
function someFunc(){
return true;
}
$x=false;
$y= $x || someFunc();
$z= $x OR someFunc();
var_dump($y);
var_dump($z);
اسکریپت نصب فونت فارسی برای لینوکس نسخه GUI
شهریور ۱۸م
قبلا یک اسکریپت نوشته بودم برای نصب فونت فارسی در لینوکس، اما اینبار میخوام همون اسکریپت رو که اینبار با zenity ایجاد شده رو بگذارم. البته این به معنی ناکار آمد بودن قبلی نیست، بلکه این یکی همون کار رو انجام میده منتها با پنجره ها و نه ترمینال.
اگر شما ترمینال رو دوست تر :)) میدارید!! اون یکی هنوز برای شما بهتره، اما اگر با پنجره سر و کله زدن رو خوشتر دارید، این یکی مطمئنا برای شماست.
در حقیقت لیست همون لیسته، wget هم همونه، ولی با کمک اسکریپتی که قبلا نوشتم برای دانلود با wget به صورت GUI و یه کم استفاده از zenity برای ایجاد لیست و …. این اسکریپت دارای GUI شده که خوب :)
این برای اجرا چند تا پیشنیاز داره :
wget برای دانلود فایلها
zenity برای نمایش پنجره ها
gksu ، چون دیگه sudo به کار نمیاد!! اگه قراره خارج از ترمینال باشه!
همه اینها به صورت پیشفرض توی اوبونتو نصبه، برای آرچ خودتون نصب کنید.
کافیه اسکریپت رو دانلود کنید،اجراییش کنید (توی گنوم، با رفتن به Properties فایل و زدن تیک مربوط به فایل اجرایی در تب Permission و یا در حالت کلی :
chmod a+x ~/bin/zfarsifonts.sh
البته با این تصور که شما اسم فایل رو میگذارید zfarsifonts.sh و اونو توی پوشه bin که توی پوشه home کاربرتون (همون ~ ) ساختید قرار گرفته.
بعد از این کار روش دوبار کلیک کنید و گزینه Run رو بزنید و دیگه باقیش که به صورت دیداری هست و شما میتونید ببینید. اسکریپت رو از آخر همین پست دانلود کنید، البته یه سری تصویر هم هست، فکر هم نمیکنم راهنما نیاز باشه!!
ادامه مطلب
ایجاد مکرر کلید جلسه
شهریور ۱۴م
در مورد جلسات این چند روزه زیاد نوشتم. تو آخرین نوشته، یه دوستی کامنت گذاشتن که استفاده از تابع session_regenerate_id میتونه کمک کنه برای جلوگیری از دزدیدن جلسه ؟ برای تست به این چیزها احتیاج هست :
اول از همه فایرفاکس
دوم فایرباگ
سوم FireCookie
چهارم یک بروزر دیگه غیر از فایرفاکس، مثلا Opera .
کدی مثل این رو ایجاد کنید :
<?php
session_start();
session_regenerate_id();
if (isset($_SESSION['test'])){
echo $_SESSION['test'];
echo "<br />";
echo session_id();
}else{
$_SESSION['test']=$_SERVER['HTTP_USER_AGENT'];
echo "First time";
}
این کد، رشته مربوط به User Agent رو توی جلسه ذخیره میکنه. بعد از دفعه اول که جلسه ایجاد بشه هر بار کلید جلسه هم نمایش داده میشه و همون رشته ذخیره شده، نمایش کلید جلسه فقط برای اینه که دسترسی به کلید جلسه یک کمی راحت شه :D
اول این کد رو توی Opera یا هر بروزری غیر از فایرفاکس اجرا کنید. البته یه Refresh نیازه که کلید و محتوا رو نشون بده.
حالا همون صفحه رو توی فایرفاکس باز کنید. دوبار هم Refresh کنید که هم کلید جلسه رو ببینید هم محتوا رو، این یکی با اون یکی فرق میکنه (طبیعیه دیگه!) حالا توو همین صفحه فایرباگ رو فعال کنید، اگه FireCookie نصب باشه یه تب داره به اسم Cookies اونجا برید، روی PHPSESSID کلیک راست کنید و گزینه Edit رو بزنید:
بعد تو دیالوگ زیر توی قسمت Value مقداری که الان توی Opera (یا هر Browser دیگه که دوست دارید) نمایش داده میشه رو کپی کنید.قبل از اینکه این مقدار کپی شده رو توی فایرفاکس بگذارید، چند بار Opera رو Refresh کنید که یه کلید جدید ساخته بشه (با کمک اون تابع session_regenerate_id ) بعد اون کلیدی که مربوط به جلسه قبل بود و کپی کردید رو توی دیالوگ زیر قسمت Value بگذارید (این دیالوگ رو گفتم، با کلیک راست روی کلمه PHPSESSID و انتخاب گزینه Edit میتونید ببینید، قسمت Host و زمان و … مهم نیست و برای هر کس متفاوته و بستگی داره به هاستی که دارید این کد رو اجرا میکنید ) اینطوری مطمئن میشید که دیگه اون کلید جلسه برای Opera از بین رفته (که البته نرفته !) :
تایید کنید و بعد یه Refresh و اونوقته که اینو میبینید :
یه مشکل دیگه این تابع، اینه که دو بار کوکی مربوط به جلسه رو توی Header میفرسته، Browser های جدید و مدرن مشکلی ندارن با این قضیه ولی مثلا روی بعضی گوشیها قاطی میکنه :)
اگر هم با آرگومان true این تابع رو فراخوانی کنیم، ممکنه مشکل از دست دادن جلسه رو داشته باشیم(توی تست من با Refresh های سریع)، بعلاوه اینکه سرعت رو هم کم میکنه، البته نسبتا.
ممنون از پیام واسه اینکه این تابع رو هم گوشزد کردن.
ذخیره جلسات در پایگاه داده
شهریور ۱۲م
دفعه قبل، درباره دزدیدن جلسه صحبت کردم، هنوز منتشر نشده که فیدبک رو ببینم) به هر صورت، این دفعه میخوام روشی رو توضیح بدم که میشه مشکل ذخیره جلسه رو در فایل سیستم حل کرد.
این راه حل آخرین راه حل در این زمینست. اگه تنظیمات سرور درست نباشه، و یه کاربر دیگه روی سیستم شما، بتونه فایلهاتون رو از طریق کاربر خودش باز کنه، خیلی راحت میتونه سورس شما رو بدزده، به دیتابیس شما دسترسی پیدا کنه و … (تنظیمات دیتابیس رو توی PHP معمولا توی فایل متنی مینویسن، خوب اگه یکی اونو باز کنه و بخونه دیتابیس هم امن نیست :) ) اگه میخواید برنامه خودتون رو منتشر کنید و نمیخواید دیگران به سورسش دسترسی داشته باشن، حتما با یه چیزی مثل Zend Guard از اون محافظت کنید، و از اون مهمتر،قیمت مهمترین فاکتور خرید هاست نیست!!!! فکر میکنم اعتماد و امنیت مهمتر باشه!
شاید بد نباشه که اول راه حل ساده تر رو نشون بدیم.
اولین مساله، اینکه مشخص کنیم آیا واقعا از آخرین دسترسی به این جلسه، یه مدت زمان خاص گذشته یا نه؟ دوم اینکه مشخص کنیم این جلسه واقعا برای همین کاربریه که الان میخواد ازش استفاده کنه؟
این کد رو ببینید :
<?php
//session_save_path("../tmp");
session_start();
//Settings
$diff=10*60; //600 Sec time out
$salt="this-is-uniq-hash-for-any-program";
$_ip=isset ($_SERVER['HTTP_CLIENT_IP'])?
$_SERVER['HTTP_CLIENT_IP'] : "UNKNOWN";
$_ip.=isset ($_SERVER['HTTP_X_FORWARDED_FOR'])?
$_SERVER['HTTP_X_FORWARDED_FOR'] : "UNKNOWN";
$_ip.=isset ($_SERVER['REMOTE_ADDR'])?
$_SERVER['REMOTE_ADDR'] : "UNKNOWN";
$_agent = isset ($_SERVER['HTTP_USER_AGENT']) ?
$_SERVER['HTTP_USER_AGENT'] : 'NO USER AGENT';
$browser_data=$salt.$_ip.$_agent;
$browser_hash=md5($browser_data);
$now=time();
if (isset($_SESSION['last_time']) && isset($_SESSION['browser_hash'])){
if (strcasecmp($browser_hash,$_SESSION['browser_hash'])!=0
|| $now-$_SESSION['last_time']>$diff){
foreach ($_SESSION as $key => $value){
unset($_SESSION[$key]);
}
session_destroy();
//You can pass to login page or whatever :-"
header("Location: ".$_SERVER['PHP_SELF']);
die(); //THIS IS IMPORTANT, never trust user browser,
}
}else{
//this is new session....
//Old session but without time and browser hash ?
//Just destroy it, if any, to prevent hijaking
foreach ($_SESSION as $key => $value){
unset($_SESSION[$key]);
}
$_SESSION['last_time']=$now;
$_SESSION['browser_hash']=$browser_hash;
}
این کد رو دقیقا در ابتدای برنامه بگذارید. دقیقا در ابتدای فایل index.php (معمولا) میتونید یه فایل جدا درست کنید این کد رو توش بنویسید و در ابتدای برنامه اینو include کنید. حالا دیگه هم زمان کنترل میشه هم بروزر، گرچه این متد بسیار بسیار سادست :) ولی خیلی هم موثره.
دقیقا اولین خط کد، که کامنت هم شده،میتونه این امکان رو به شما بده که جای ذخیره شدن جلسات رو عوض کنید، مثلا بیاریدشون روی پوشه های خودتون(که البته باید یه فولدری باشه که وب سرور بهش دسترسی نداشته باشه، یعنی یا با htaccess یا با هر ابزار دیگه ای کاملا قفلش کرده باشید یا اینکه اصلا خارج از پوشه ریشه باشه. البته این پوشه باید توسط PHP قابل نوشتن باشه که بتونه جلسات رو اونجا ذخیره کنه. اگر نه یکی از بیرون و به راحتی از طریق Browser میتونه فایل رو ببینه)
اما راه دوم، که به شما این امکان رو میده که مثلا جلسات رو توی دیتابیس ذخیره کنید، نه توی فایل. از PDO برای دیتابیس استفاده شده.
ادامه مطلب








