PDA

View Full Version : سوال: Escape کردن تعداد زیادی متغیر



amin7x
دوشنبه 06 خرداد 1392, 11:15 صبح
سلام دوستان
من حدودا توی هر متدی باید 7 یا 8 متغیر رو Escape کنم.
راهی نداره که من این متغیر ها رو با هم Escape کنم و دیگه دونه دونه این کارو نکم؟

منظورم به جای این کار :


mysql_real_escape_string($Var1);
mysql_real_escape_string($Var2);
mysql_real_escape_string($Var3);
mysql_real_escape_string($Var4);

یه کاری شبیه به این کرد :



mysql_real_escape_string($Var1,$Var2,$Var3,$Var4);


ممنون

H:Shojaei
دوشنبه 06 خرداد 1392, 11:24 صبح
سلام مقادر رو تو آرايه بذاريد آرايه رو با يه تابع كه توش يه حلقه هست escape كنيد.

H:Shojaei
دوشنبه 06 خرداد 1392, 11:31 صبح
مثال از PHP.net:


for...
// Check if the nodes are strings
if(is_string($array[$key]))
// If they are, perform the real escape function over the selected node
$array[$key] = mysql_real_escape_string($array[$key]);

MMSHFE
دوشنبه 06 خرداد 1392, 11:48 صبح
list($var1, $var2, $var3, $var4) = array_map('mysql_real_escape_string', array($var1, $var2, $var3, $var4));

H:Shojaei
دوشنبه 06 خرداد 1392, 12:37 عصر
سلام
درباره ي اين تابع(array_map) تو PHP.net هم نگاه كردم ولي چيزي نفهميدم كه كاربردهاش چيه.
array_map in php.net (http://www.php.net/manual/fr/function.array-map.php)
ميشه يه توضيح مختصر درباره ي پارامتر هاش بدين ممنون.

MMSHFE
دوشنبه 06 خرداد 1392, 12:59 عصر
اسم یک تابع و یک آرایه رو میگیره و یکی یکی مقادیر آرایه رو میفرسته به اون تابع و خروجی رو دوباره بصورت یک آرایه برمیگردونه.

matrixhassan
دوشنبه 06 خرداد 1392, 16:56 عصر
با اجازه از استارتر
با سلام میخواستم بدون کد دیگه ای هست که جایگزین این mysql_real_escape_string کرد انگار این کد زیاد معتبر نیست دیگه ؟

MMSHFE
دوشنبه 06 خرداد 1392, 17:04 عصر
دوست گرامی این کد رو طبق چه سندی میگین معتبر نیست؟

matrixhassan
دوشنبه 06 خرداد 1392, 17:20 عصر
من تو انجمن آشیانه یه جا خوندم که این کد تقریبا نمیتونه تمام کدها رو اسکیپ کنه و دوم نمیدونم اینگار سایت خود php بود که گفته بود قرار این کد کنار گذاشته بشه ؟

eshpilen
دوشنبه 06 خرداد 1392, 21:29 عصر
mysql_real_escape_string یکی از توابع کتابخانهء کلاینت قدیمی MySQL است. منظورم از کتابخانهء کلاینت، کتابخانه ای است که برای ارتباط با برنامهء سرور MySQL استفاده میشه.

برای ارتباط با MySQL مدتهاست که کتابخانه ها و روشهای جدیدتری وجود دارن. مثل MySQLi و PDO. این کتابخانه ها جدیدتر هستن و مزایایی دارن بالاخره مثل سرعت و بهینگی بیشتر، یا امکاناتی مثل کوئری های پارامتری و Prepared statement، که اینها به برقراری راحتتر امنیت و کمتر شدن خطای برنامه نویس در این زمینه هم خیلی کمک میکنن.

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

از نظر امنیت هم mysql_real_escape_string مشکلی نداره ولی چندتا نکته و ظرافت داره که برای برنامه نویس، خصوصا افراد دارای دانش و مهارت ناکافی در امنیت و برنامه نویسان تازه کار، میتونه خیلی راحت موجب خطای انسانی و در نتیجه حفرهء امنیتی بشه.
اگر بلد باشید اون نکات رو و دقت کافی داشته باشید، از نظر امنیتی مشکلی پیش نمیاد. البته حتی برای برنامه نویسان حرفه ای هم بهرحال ممکنه این نکات و نیاز به دقت بیشتر، گاهی دردسرساز بشه و چیزی از زیر دستشون در بره، بخاطر همین استفاده از این روش Escape کردن دیگه توصیه نمیشه و بجاش استفاده از روش کوئری های پارامتری و اینها توصیه میشه.

ضمنا حتی در اون کتابخانه های دیگر هم تاجاییکه دیده بودم تابع معادل همین mysql_real_escape_string وجود داره. یعنی به احتمال زیاد دقیقا همین تابع است فقط در قالب اون کتابخانه های جدید.

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

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

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

هرچی نکاتی که برنامه نویس باید بدونه و موقع کدنویسی متوجه اونا باشه و دقت و مدیریت کنه کمتر باشن، طبیعتا ریسک خطای انسانی کمتر میشه و بنابراین ریسک امنیتی هم کمتر میشه.

eshpilen
دوشنبه 06 خرداد 1392, 22:04 عصر
من تو انجمن آشیانه یه جا خوندم که این کد تقریبا نمیتونه تمام کدها رو اسکیپ کنه و دوم نمیدونم اینگار سایت خود php بود که گفته بود قرار این کد کنار گذاشته بشه ؟
بیشتر این آدمها سواد واقعی ندارن همینطور یه چیزی یه جایی میخونن یا از یه هکر قویتر، بعد میان مثل طوطی تکرار میکنن.
یعنی طرز کار و علت رو واقعا درک نکردن.
این افراد نهایت درجهء Script kiddie رو دارن!
از کدها و طرز کار سطح پایین سردرنمیارن.
براشون یک Black box و جعبه جادویی و کد خطرناک و کاراکتر خطرناکه اینطور چیزها؛ چیز بیشتری ازش نمیدونن.
وای الان چقدر بد و بیراه بهشون گفتم حتما میخوان ازم انتقام بگیرن :لبخند:

بنده توصیه میکنم بجای استفادهء مستقیم از mysql_real_escape_string، از این تابع استفاده کنید:

function quote_smart($value) {

if(!is_numeric($value)) return "'" .mysql_real_escape_string($value) . "'";
else return $value;

}
یا بهرصورت تابعی شبیه این که عدد رو همونطور بازگشت بده و هرچی رو که شبیه عدد نباشه اسکیپ کنه و توی کوتیشن بذاره.

یه نقطه ضعف دیگر هم در mysql_real_escape_string بود که مربوط به charset های خاصی میشد: http://stackoverflow.com/a/12118602
البته به احتمال زیاد این ضعف در برنامه های کسی وجود نداره چون فقط درصورتی که از بعضی از کاراکترست های خاص (نه UTF-8) استفاده کنید این ضعف امکان بروز پیدا کردن داره.
بهرحال راه حل این ضعف هم روشن و ساده است.
راه حل اینه که بجای استفاده از این کوئری برای ست کردن کاراکترست:

SET NAMES 'utf8'
از این دستور استفاده کنید:

mysql_set_charset('utf8')

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

البته راه اصولی تر بقول متخصصان، اینه که استفاده از این تابع رو کلا کنار بذارید و از روشهای توصیه شده استفاده کنید.
ولی اگر یک برنامه ای دارید که قبلا با این روش نوشته شده، نیازی به تغییر و بازنویسی اون نیست.
یا شاید به هر علتی بازم ترجیح میدید از این تابع استفاده کنید. خب مثل اینه که کسی بگه من هنوزم میخوام بدون شیء گرایی برنامه بنویسم یا MVC استفاده نکنم. کسی نمیتونه بگه نه تو حتما همیشه و در هر موردی باید از شیء گرایی یا الگوهای طراحی استاندارد استفاده کنی. جرم که نکرده! کفر که نگفته! کار خودشه و شرایط خودش رو داره در نهایت خودش بهتر میدونه و تصمیمگیری باید با خودش باشه. ممکنه برنامه ای هم بنویسه که هیچ نقص و ضعف مهمی نداشته باشه.

xcodex
دوشنبه 06 خرداد 1392, 22:18 عصر
با سلام از تابع array_walk (http://www.w3schools.com/php/func_array_walk.asp) هم میشه استفاده کرد

یا حق

MMSHFE
سه شنبه 07 خرداد 1392, 08:31 صبح
من تو انجمن آشیانه یه جا خوندم که این کد تقریبا نمیتونه تمام کدها رو اسکیپ کنه و دوم نمیدونم اینگار سایت خود php بود که گفته بود قرار این کد کنار گذاشته بشه ؟
زیاد به حرفهای آشیانه توجه نکنید. البته نه فقط آشیانه، کلاً به حرفی که فقط یکنفر میگه توجه نکنید. باید چندین منبع معتبر تأیید کنن و مدرک ارائه بدن. مثلاً اگه آشیانه گفته نمیتونه تمام کدها رو Escape کنه، یک مثال هم بگذاره و خودتون مثال رو تست کنید و ببینید درست میگن یا نه چون ممکنه توی نسخه های بعدی PHP اون نقص رفع شده باشه. ضمناً توی سایت PHP گفته شده که کلاً افزونه MySQL داره با MySQLi جایگزین میشه و از اونجا که توی MySQLi و PDO عمل Escapeکردن یه جورایی توکار شده، دیگه بهش نیازی نیست نه اینکه mysql_real_escape_string کارآیی نداشته باشه. البته استفاده از mysql_real_escape_string هم اصول خاص خودش رو داره. مثلاً کوئری رو هم باید استاندارد بنویسید. برای مثال، اسامی فیلدها و جداول و... حتماً توی Back Quote ( ` ) نوشته بشه یا مقادیر حتماً توی Single Quote ( ' ) قرار بگیره یا شرط WHERE حتماً توی پرانتز قرار بگیره و... در غیر اینصورت، کوئری شما بازهم آسیب پذیره منتها نه بخاطر اینکه mysql_real_escape_string نتونسته وظیفه خودش رو درست انجام بده، بلکه به این خاطر که شما کوئری استاندارد و ایمن ننوشتین.

eshpilen
سه شنبه 07 خرداد 1392, 11:45 صبح
برای مثال، اسامی فیلدها و جداول و... حتماً توی Back Quote ( ` ) نوشته بشه یا مقادیر حتماً توی Single Quote ( ' ) قرار بگیره یا شرط WHERE حتماً توی پرانتز قرار بگیره و...
البته Escape کردن عادی فقط برای مقدارها امنه.
جاهای دیگه مثل اسامی فیلد و جدول و اینها نکات امنیتی خودش رو داره و Escape به تنهایی به این معنی نیست که امنیت تامین شده.
در منابع امنیتی که دیدم اصولا توصیه میکنن از ساخت این قسمتهای کوئری بر اساس ورودیهای کاربر و هر دادهء غیرقابل اعتماد حتی الامکان اجتناب بشه.
یوقت هم اگر مجبور باشیم، مثلا درمورد اسم فیلد برای sort کردن، باید حتی الامکان از روشهایی مثل White list استفاده کرد.
mysql_real_escape_string هم اصولا برای Escape کردن value ها طراحی شده، نه چیزهای دیگری مثل identifier ها. بخاطر همین این تابع اصولا کاری به Back Quote نداره. در نتیجه Escape کردن یه چیزی مثل اسم فیلد با این تابع، درمقابل SQL injection امنیت ایجاد نمیکنه.

MMSHFE
سه شنبه 07 خرداد 1392, 12:00 عصر
میدونم. من بطور کلی استاندارد نوشتن کوئری مدنظرم بود وگرنه mysql_real_escape_string فقط به Valueها کار داره و اصلاً به اصول نامگذاری Identifierها کاری نداره. برای مثال، اگه اسامی فیلدها و جداول رو توی Backquote نگذارین و اونوقت یک فیلد به اسم date داشته باشین، کوئری شما ممکنه با خطا مواجه بشه چون MySQL نمیدونه منظورتون فیلد date بوده یا تابع date

MMSHFE
سه شنبه 07 خرداد 1392, 12:01 عصر
با سلام از تابع array_walk (http://www.w3schools.com/php/func_array_walk.asp) هم میشه استفاده کرد
array_walk خروجی آرایه نداره. فقط تابع رو یکی یکی روی مقادیر آرایه اجرا میکنه و خروجی رو دوباره بصورت آرایه بر نمیگردونه.

xcodex
سه شنبه 07 خرداد 1392, 13:20 عصر
array_walk خروجی آرایه نداره. فقط تابع رو یکی یکی روی مقادیر آرایه اجرا میکنه و خروجی رو دوباره بصورت آرایه بر نمیگردونه.
ممنون ولی قرار نیست آرایه برگردونه

به این کد نگاه کنید :



$items=array("key1"=>"value1","key2"=>"value2");

array_walk($items,sanitize);

function sanitize(&$value){
$value=mysql_real_escape_string($value)
}
print_r($items);


با استفاده از & میشه خیلی راحت مقادیر رو sanitize کرد و احتیاج نیست متغیر جدیدی تعریف بشه.

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

یا حق

MMSHFE
سه شنبه 07 خرداد 1392, 14:33 عصر
درسته میشه استفاده کرد ولی بین دو کد زیر، به نظرتون کدوم یکی خلاصه تره:


function sanitize(&$value) {
$value = mysql_real_escape_string($value);
}
array_walk(array($var1, $var2, $var3, $var4), 'sanitize');

و این کد:

list($var1, $var2, $var3, $var4) = array_map('mysql_real_escape_string', array($var1, $var2, $var3, $var4));
قطعاً array_walk کاربردهای خاص خودش رو داره و تابع بسیار سودمندی هست ولی فکر میکنم در این مورد array_map بهینه تره. بعلاوه همون کد بالایی هم فکر نمیکنم کار کنه چون کپی متغیرها توی آرایه است نه اصلش. منظورم اینه که درسته که تابع شما با & داره روی مقادیر اصلی کار میکنه ولی همون مقادیر اصلی، کپی مقایر موردنظر ماست نه اصلش. مگه اینکه اینطوری کار کنیم:


function sanitize(&$value) {
$value = mysql_real_escape_string($value);
}
$array = array($var1, $var2, $var3, $var4);
array_walk($array, 'sanitize');
list($var1, $var2, $var3, $var4) = $array;

که اوضاع بدتر میشه! اصلاً همین که یک تابع اضافه شده (sanitize) و ازطریق اون باید یک تابع دیگه (mysql_real_escape_string) رو صدا بزنیم، خودش یکجور عدم بهینگی هست.

xcodex
سه شنبه 07 خرداد 1392, 16:05 عصر
اینکه فرمودین کد کار نمیکنه فکر نمیکنم کار نکنه چون شما یه آرایه دارید که مقادیرش بعد از sanitize شدن جایگزین مقادیر قبلی میشن.

حرف شما در مورد بهینه بودن کاملا تایید میشه و کد شما بهینه تر عمل میکنه در این مورد.

ممنون از راهنمایی و دقت نظرتون

MMSHFE
سه شنبه 07 خرداد 1392, 20:18 عصر
بحث عدم کارکرد مناسب هم هست. به کد زیر دقت کنید:


function sanitize(&$value) {
$value = mysql_real_escape_string($value);
}
array_walk(array($var1, $var2, $var3, $var4), 'sanitize');

توی کد فوق، درسته که وجود & در پارامتر تابع باعث میشه تغییرات توی تابع دقیقاً توی خونه های آرایه ای که بعنوان آرگومان ارسال شدن، اعمال بشه ولی باید دقت کنید که خود مقادیر این آرایه، یک کپی از مقادیر $var1 و... هستن و نه خود اون مقادیر. بنابراین ما داریم روی نسخه کپی مقادیر کار میکنیم. مگه اینکه دوباره بیایم اون آرایه رو توی خود مقادیر اصلی کپی کنیم:


function sanitize(&$value) {
$value = mysql_real_escape_string($value);
}
$array = array($var1, $var2, $var3, $var4);
array_walk($array, 'sanitize');
list($var1, $var2, $var3, $var4) = $array;

البته کد شما به این شکل هم کار میکنه:


function sanitize(&$value) {
$value = mysql_real_escape_string($value);
}
array_walk($_POST, 'sanitize');

یعنی Escape کردن کل آرایه POST_$ ولی طبق صحبتهای ایجادکننده تاپیک، ایشون میخوان همون چندتا مقداری که دارن رو Escape کنن و نه لزوماً تمام مقادیر آرایه POST_$ رو. امیدوارم منظورم رو رسونده باشم.

xcodex
چهارشنبه 08 خرداد 1392, 09:12 صبح
بله حرف شما کاملا تایید میشه .

البته با یه تابع extract هم میشه آرایه sanitize شده رو تبدیل به متغیر ها کرد که یه جورایی لقمه دور سر چرخوندنه !

ولی کاملا با نظر شما موافقم ممنون از شما.

amin7x
چهارشنبه 08 خرداد 1392, 12:26 عصر
البته استفاده از mysql_real_escape_string هم اصول خاص خودش رو داره. مثلاً کوئری رو هم باید استاندارد بنویسید. برای مثال، اسامی فیلدها و جداول و... حتماً توی Back Quote ( ` ) نوشته بشه یا مقادیر حتماً توی Single Quote ( ' ) قرار بگیره یا شرط WHERE حتماً توی پرانتز قرار بگیره و... در غیر اینصورت، کوئری شما بازهم آسیب پذیره منتها نه بخاطر اینکه mysql_real_escape_string نتونسته وظیفه خودش رو درست انجام بده، بلکه به این خاطر که شما کوئری استاندارد و ایمن ننوشتین.

سلام
ممنون از همه دوستان که کمک کردن.
من برنامه هام رو به صورت شی گرا (البته دست و پا شکسته) مینویسم.
خب با ویرایش 3 یا 4 تا خط کد میرم به سمت PDO که دیگه از شر Escape خلاص بشم.

فقط یک سوال در مورد نقل و قول بالا ، میخواستم بدونم منبع ای هست که همه این اصول توش باشه؟

MMSHFE
چهارشنبه 08 خرداد 1392, 13:21 عصر
منبع رسمی و خاصی نیست ولی میتونید با مشاهده ساختار Queryهایی که توی dev.mysql.com نوشته شده، تا حدودی با اصول استانداردنویسی آشنا بشین. البته کوئریهای تولیدشده توسط PHPMyAdmin هم استاندارد هستن.