برنامه نويسي امن

oxygenws

Active Member
علیرضا، منظورت چیه؟؟ بیشتر توضیح بده.

امیدک جان، من مشکلی با .net شدن هم ندارم، ولی دوست دارم حداقل یک مطلب درست و حسابی در اون مورد باشه. برای اینکه منظورم رو بفهمی..... ترجیح می دم یه سری قانون اینجا بنویسم:
1- در هر پست فقط یک مشکل امنیتی مطرح یشه.
2- در بالای هر مطلب آموزشی تیتری مشابه زیر نوشته بشه:
روش: SQL Injection
سطح: متوسط
زبان: PHP
بانک اطلاعاتی: MySQL
حد خطر: زیاد
قسمت: 2
که "روش" نام روش در مجامع عمومی رو در بر داره (یا حداقل یه نام ساده و "سطح" سادگی یا دشواری مطلب، "زبان" هم که زبان برنامه نویسی مربوطه، "بانک اطلاعاتی" هم در صورت وجود داشتن بانک، اون رو نام می برید، این گزینه بیشتر برای مثال هایی که در مقاله استفاده می شه کاربرد داره و قسمت، که وابسته به مقالات قبلی بوده و شمارهء اون به ترتیب زیاد می شه. البته بد نیست یک "حد خطر" هم گذاشته بشه که می تونه مقادیر "زیاد"، "متوسط" و "کم" داشته باشه.
3- موارد باید کاملا مربوط به برنامه نویسی باشه.
4- مشکلات به وجود اومده توسط رعایت نکردن این مطلب حتما باید گفته بشه.
5- گفته شدن دلیل منطقی به وجود اومدن مشکل. (این با مورد 4 تقریبا یکی است)
6- روش رفع مشکل توسط زبان و بانک اطلاعاتی گفته شده در تیتر مقاله.

اگه قانون های فوق فکر می کنید کمه، بگید تا اضافه اش کنیم :)

اگر اولین مقاله با این قوانین برای زبانی به غیر از php اینجا گذاشته شد.... خوب، اسم اینجا رو هم عوض می کنیم. از برنامه نویسان محترم asp و asp.net و jsp و perl و cold fusion و c و ... هم می خوام که بیان و بنویسند :)

موفق باشید، امید
 

Ealireza

Member
روش: Hashing
سطح: متوسط
زبان: ASP
بانک اطلاعاتی: Access/Sql
حد خطر: متوسط
قسمت: 4


ميدونين كه هر كلمه رمز يا ... به راحتي ازيك بانك Access قابل خوندنه و اين باعث ميشه كه به راحتي به رمز عبور ها دسترسي داشت
اما وقتي كه رمز يا نام كاربري Hash شود ديگر خطر بر طرف ميشود

در صورتي كه از hash استفاده شود يك چارت مانند ' يا " كلا كد شده و مثلا
کد:
04b654s4vFF1v
در مي آيد كه اين خود بسيار مهم ميياشد :wink:
 

oxygenws

Active Member
علیرضا جان، خوب بود.... فقط یه مثال از تابع یا توابعی هم که برنامه نویس رو کمک می کنه تا کدش امن بشه بنویس. :)

من تیتر مطلب رو هم تا 2 دقیقه دیگه عوض می کنم.
 

omidak

Active Member
سلام:
اميد راست رو بخوايي فكر نميكنم بجز اينايي كه گفتم تويه .Net نفوز دیگه ای وجود داشته باشه :lol:
مگر انیکه طرف بیاد بگه با فشار این لینک تمام اطلاعات Database حذف میشود:
Delete From myTable
:lol: :lol: :lol: :lol: :wink:
 

oxygenws

Active Member
omidak گفت:
سلام:
اميد راست رو بخوايي فكر نميكنم بجز اينايي كه گفتم تويه .Net نفوز دیگه ای وجود داشته باشه :lol:
مگر انیکه طرف بیاد بگه با فشار این لینک تمام اطلاعات Database حذف میشود:
Delete From myTable
:lol: :lol: :lol: :lol: :wink:

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

ممنون امید، سعی کن مطلب مفید بنویسی امید جان، لطفا آف تاپیک نذارید.

شرمنده که زیاد حرف زدم.
موفق باشید، امید
 

omidak

Active Member
سلام:
خوب بفرما اميد جان ديدي نسنجيده گفتي. :roll:
.Net یه سیستمی داره به نام HTML Filter :roll: که در شاخه UI هست.
من هم که یه چیزی رو میگم مطمعن ام و میگم. :wink:

امید هی غور بزن :roll:
 

Majid

مدیر سایت
عضو کادر مدیریت
روش: Include
سطح: مقدماتي
زبان: PHP
حد خطر: بالا
قسمت: 5



هرگز فايل يا نوشته اي را که از کاربر دريافت شده است را مستقيما ()include() , require و يا open نکنيد مگر اينکه از قبل آنرا بررسي کرده باشيد. به عنوان مثال فرض مي کنيم page$ فايلي است که کاربر وارد مي کند و ما قصد ()include کردن آنرا داريم.

کد:
if (isset($page)) 
{ 
include($page);
}



در اين مثال از آنجا که ما page$ را از قبل بررسي نکرده ايم ، کاربر براحتي مي تواند کدهاي ناخواسته و محرمانه ديگر ما را نيز صدا بزند. مثلا :


کد:
script.php?page=/etc/passwd


بنابراين ممکن است فايل ناخواسته اي که حاوي پسوردهاي شماست ()include شده و به نمايش در آيد. همانطور که مي دانيم وقتي يک کد غير php در آن ()include مي شود اين زبان به صورت پيش فرض آنرا HTML يا Text در نظر مي گيرد. پس به همين راحتي ممکن است صفحه ناخواسته اي بر روي سرور شما که شامل پسورد هم مي باشد به نمايش درآيد.

از طرف ديگر مي دانيم که تابع هاي ()include و ()require در php قابليت دريافت يک فايل از راه دور را دارا هستند. حال اگر کاربري فايلي مثل اين را صدا بزند :


کد:
script.php?page=http://mysite.com/MyScript.php



از اين طريق کاربر قادر خواهد بود تا هر کدي که مي خواهد در سايت شما صدا بزند. به فرض اگر او بخواهد مقداري از اطلاعات شما را پاک کند يا حتي اطلاعات حساسي را مستقيما در صفحه قرار دهد.

حال راه حل چيست؟ مسلما جاي ترديد نيست که در وهله اول بايد ورودي را مورد بررسي قرار دهيم! مثلا ليستي از صفحه هاي قابل قبول را تهيه کنيم و اگر ورودي با آن تطابق نداشت يک error نمايش دهيم.


کد:
$pages = array('index.html', 'page2.html', 'page3.html'); 
if (in_array($page,$pages)) 
{ 
include($page); 
{ 
else 
{ 
die("Sorry, Invalid file."); 
}



همانطور که ديديد در اين مثال ليستي از صفحه هاي قابل قبول را در آرايه اي به نام pages$ مي ريزيم و اگر صفحه ورودي در آرايه وجود داشت آنرا ()include مي کنيم. (در غير اين صورت پيغام Sorry, Invalid file را نمايش مي دهيم )


http://security.majidonline.com/phpsm/phpsm2.htm


مجيد
 

Majid

مدیر سایت
عضو کادر مدیریت
روش: تابع EVAL
سطح: متوسط
زبان: PHP
حد خطر: متوسط
قسمت: 6


هنگام کار با تابع ()eval بسيار دقت کنيد.
هرگز مقادير گرفته شده از کاربر را مستقيما در اين تابع قرار ندهيد. با قرار دادن آن، در واقع شما او را توانمند ساخته ايد که هر دستوري که مي خواهد به اجرا درآورد. يک drop-down منو با انتخابهاي معيني را فرض کنيد، کاربر ممکن است به جاي انتخاب هاي پيش فرض چيزي مثل اين را وارد کند :


کد:
script.php?input=;passthru("cat /etc/paswd");


او با قرار دادن اين کد براحتي مي تواند ليست کاملي از فايل /etc/passwd شما دريافت کند.

سعي کنيد کمتر از تابع ()eval استفاده کنيد مگر اينکه مجبور باشيد کد php را به صورت dynamic توليد کنيد که در اين صورت حتما ورودي را از هر نظر بررسي کنيد. اگر شما از اين تابع براي جانشين سازي متغير هاي template در يک string يا جانشين سازي مقادير ورودي توسط کاربر استفاده مي کنيد ، بهتر است از توابعي مثل ()sprintf يا template system سود جوييد.

http://security.majidonline.com/phpsm/phpsm3.htm



مجيد
 

Majid

مدیر سایت
عضو کادر مدیریت
روش: سو استفاده از register_globals
سطح: مبتدي
زبان: PHP
بانک اطلاعاتی: ---
حد خطر: متوسط
قسمت: 7


(اين موضوع رو sarallah عزيز قبلا گفته بودند من فقط تكميلش ميكنم)


بهتر است که register_globals را بطور پيش فرض روي off قرار دهيد. (register_globals=OFF)

در ابتدا register_globals براي راحت تر کردن کار برنامه نويس مطرح شدند ولي چندي نگذشت که تبديل به حفره ي امنيتي بزرگي شدند. به همين دليل از ورژن 4.2 php به بعد register_globals را به صورت default روي OFF قرار گرفته است. بهتر و امن تر است که از ورودي هاي superglobals استفاده کنيد. به عنوان نمونه :
( $_GET , $_POST , $_COOKIE )


براي مثال متغيري به نام page$ را در نظر بگيريد که مي خواهيم آنرا در صفحه خود ()include کنيم. حال اگر فراموش کرده باشيم که اين متغير را تعريف کنيم ( مقداري در آن قرار نداده باشيم) و register_globals روي ON قرار گرفته باشد، کاربر محترم به راحتي مي تواند سودجويي کرده و اين متغير را مطابق ميل خود تعريف کند. مثلا :


کد:
script.php?page=http://www.example.com/His-script.php



به همين علت توصيه شده که register_globals را به صورت پيش فرض روي OFF قرار داده و از superglobals استفاده کنيم.

علاوه بر اين بهتر است که هميشه تمام error ها را نمايش دهيم.

کد:
error_reporting(E_ALL);



بدين صورت هر گاه شما متغيري را صدا کنيد که از قبل تعريف نشده پيغام خطايي دريافت خواهيد کرد.




http://security.majidonline.com/phpsm/phpsm4.htm


مجيد
 

Majid

مدیر سایت
عضو کادر مدیریت
روش: SQL Injection
سطح: متوسط
زبان: PHP
بانک اطلاعاتی: MySQL
حد خطر: زیاد
قسمت: 8



(اين مشكل رو هم قبلا آقا اميد oxygenws گفتند من فقط يكم تكميلش ميكنم)

همانطور که مي دانيم يکي از ويژگي هاي php اين است که وقتي character معيني را از GET,POST يا Cookie دريافت مي کند به آن يک \ اضافه مي کند. (مثلا کاراکتر ' )(single quote)

اين ويژگي بدين منظور است که اگر شما به فرض بخواهيد متغير ورودي را مستقيما در يک sql query قرار دهيد، در ساختار اوليه query تغييري صورت نگيرد. فرض کنيد مي خواهيم از طريق يک فرم متغير name$ ( که اسم کاربر است ) را دريافت کرده و در اين query قرار دهيم :

کد:
UPDATE my_table SET Name='$name' WHERE ID=1



در حالت عادي اگر اسم شخص حاوي کاراکتر ' باشد ، php آنرا ناديده گرفته و بصورت (\') در query قرار مي دهد. به طور مثال اگر شخص اسم خود را به صورت Taher's وارد کند php خود به خود آنرا به Taher\'s تبديل کرده و در query قرار مي دهد. پس خواهيم داشت :


کد:
UPDATE my_table SET Name='Taher\'s' WHERE ID=1



گاهي ممکن است از تابع stripslashes براي تصحيح مقادير ورودي استفاده کنيم. ولي توجه داشته باشيد که اگر مي خواهيد مقدار آنرا مستقيما در يک query قرار دهيد حتما از قبل، آنرا از توابعي مثل addslashes يا mysql_escape_string بگدرانيد. اهميت اين امر را با مثالي ساده توضيح خواهم داد.

با توجه به مثال قبل، تصور کنيد که مقدار ورودي را از اين توابع نگذرانده ايم. حال اگر کاربر محترمي اسم خود را به اين صورت وارد کند :


کد:
Taher',admin='1



چه اتفاقي خواهد افتاد ؟ اگر اين مقدار name$ را در query خود جايگزين کنيم خواهيم داشت :


کد:
UPDATE my_table SET Name='Taher',admin='1' WHERE ID=1



خوب، به همين راحتي!
پس از اين جهت توابع ذکر شده اهميت مي يابند.


در بعضي از configuration ها تابع ()magic_quotes_gpc بطور پيش فرض روي off قرار گرفته است. براي کسب اطمينان از .config خود مي توانيد از تابع ()get_magic_quotes_gpc استفاده کنيد. (اين تابع مقدار true يا false را باز مي گرداند).

اگر خروجي اين تابع false بود به راحتي مي توانيد از تابع ()addslashes سود ببريد.(اگر از ورودي هاي
$_GET, $_COOKIE , $HTTP_POST_VARS, $HTTP_GET_VARS, $HTTP_COOKIE_VARS
استفاده مي کنيد بهترين راه استفاده از تابع ()addslashes مي باشد)


http://security.majidonline.com/phpsm/phpsm5.htm


مجيد
 

Majid

مدیر سایت
عضو کادر مدیریت
روش: Cookie و SESSION به جاي متغير
سطح: پيشرفته
زبان: PHP
بانک اطلاعاتی: -------
حد خطر: زیاد
قسمت: 9


برنامه نويس ممکن است براي محدود کردن صفحه هايي از سايت خود از cookie ها استفاده کرده يا اينکه يک متغير پنهاني را تعريف نموده و صدا بزند. بطور مثال :
کد:
if ($admin) 
{ 
// ادامه کد 
} 
else 
{ 
// Boro biroon 
}



اگر پسورد وارد شده صحيح بود مقدار admin$ را true قرار داده و بدين شکل از آن استفاده مي کنيم. اشکال وارد به اين روش اين است که مقدار admin$ از راههاي مختلفي ممکن است تعيين شود. فرض اگر کاربر ما چنين چيزي را صدا بزند

کد:
script.php?admin=1



به همين سادگي او مقدار admin را true وضع کرده و مي تواند از ضعف کد ما سوء استفاده کند.
حتي اگر از superglobals استفاده کرده باشيم او مي تواند فرم html را خود طراحي کند يا يک cookie ايجاد کند.

دو راه براي حل اين مشکل وجود دارد. يکي آنکه متغير admin$ را به صورت session در نظر بگيريم. همانطور که مي دانيم متغير session بر روي سرور ذخيره مي شود و امنيت بالاتري را ايجاب مي کند. بدين طريق اطلاعات session بر روي سرور قرار خواهند داشت و مي توان بوسيله آن وضعيت يک کاربر را مشخص کرد :


کد:
if ($_SESSION['admin'] )



راه حل دوم اين است که username و password را در cookie بريزيم و هر دفعه با بررسي آن از تطابق آن با پسورد اصلي مطمئن شويم. همچنين با مقايسه آن مي توانيم تعيين کنيم که آيا کاربر admin است يا يک کاربر معمولي. با استفاده از دو تابع اين کار ميسر است. يکي آنکه صحت username و password وارد شده را تشخيص دهد و ديگري آنکه تعيين کند آيا اين داده ها مربوط به admin هستند يا کاربر.
فرض کنيد اين دو تابع را validate_login و is_admin بناميم. بنابراين :
کد:
if (!validate_login($_COOKIE['username'], $_COOKIE['password'] ) ) 
{ 
echo "Sorry, invalid login"; 
exit; 
} 
// اطلاعات کاربر صحيح است ، ادامه برنامه 
if (!is_admin($_COOKIE['username'] )) 
{ 
echo "Sorry, you do not have access to this section"; 
exit; 
}



( من به خاطر کارآيي بيشتر session به شخصه راه حل اول را توصيه مي کنم )


http://security.majidonline.com/phpsm/phpsm6.htm


مجيد
 

Majid

مدیر سایت
عضو کادر مدیریت
روش: نام گذاري اشتباه فايل
سطح: مقدماتي
زبان: هر زبان تحت سرور
بانک اطلاعاتی: -------
حد خطر: متوسط
قسمت: 10



اگر نمي خواهيد که محتويات فايل به نمايش در آيد به آن پسوند php. بدهيد!

مدتي معمول بود که فايل هايي را که مي بايست include ميشدند را با پسوند inc. نامگذاري مي کردند. مشکل کار اينجاست که اگر کاربر مستقيما آدرس فايل inc را صدا بزند محتويات آن همانند يک فايل text نمايش داده مي شود. يا اينکه فايل براحتي مي تواند توسط کاربر دانلود شود. حال ممکن است فايل حاوي username و password ديتابيس شما يا اطلاعات حساس ديگري باشد!

مسلما راه حل دادن پسوند php. مي باشد. از آنجا که فايل هاي inc معمولا خروجي ندارند اگر به آنها پسوند php بدهيم هنگام صدا زدن آن چيزي نمايش داده نخواهد شد. مثلا اگر فايلي به نام lib.inc داريم کافيست php را هم به آن اضافه کنيم. پس :


کد:
http://yoursite.com/lib.inc.php




http://security.majidonline.com/phpsm/phpsm7.htm


مجيد
 

Majid

مدیر سایت
عضو کادر مدیریت
روش: چك كردن محل درخواست برنامه
سطح: متوسط
زبان: PHP
بانک اطلاعاتی: -------
حد خطر: كم
قسمت: 11


با اينکه فرم ها در جمع آوري اطلاعات و داده هاي کاربر بسيار مفيد هستند ولي اولين نقطه براي نفوذ به شمار مي روند. در اين مورد بايد اطمينان حاصل کنيم که اطلاعات از فرم مورد نظر ما به سايت وارد مي شوند. ( نه از جايي ديگر، مانند فرم ساخته شده توسط کارير)

يک راه حل مناسب اين است که از ['SERVER['HTTP_REFERER_$ استفاده کنيم و بررسي کنيم که اطلاعات از کجا مي آيند. همانطور که مي دانيم HTTP_REFERER آدرس صفحه اي را که اطلاعات از آنجا به برنامه ما ارسال شده اند مشخص مي کند. پس از اين طريق مي توانيم آدرس صفحه را با آنچه مد نظر ماست مقايسه کنيم.
( فرض کنيد فرم ما در اين آدرس قرار گرفته است : domain.net/my_form.html )

کد:
// آدرس فرم ما
$my_form_URL = "http://domain.net/my_form.html"; 

// آدرس ورودي 
$incoming_URL = $_SERVER['HTTP_REFERER']; 

if ($my_form_URL == $incoming_URL) { 
// همه چيز درست است، ادامه برنامه 
} else { 
// يه نفر قصد اذيت داره 
echo "Access Denied."; 
exit;


همانطور که ديديم در صورتي که آدرس ورودي با http://domain.net/my_form.html تطابق نداشته باشد پيغام Access Denied به نمايش در خواهد آمد و ادامه کد اجرا نخواهد شد (;Exit)
از اين طريق شما به راحتي مي توانيد بر صفحه ورودي کنترل داشته باشيد.


http://security.majidonline.com/phpsm/phpsm8.htm


مجيد
 

NabiKAZ

Well-Known Member
سلام
من PHP مينويسم ، نكته هاي شما حسابي منو ترسوند ! چون من به اين نكته هاي مهم هيچ وقت دقت نكرده بودم .
خيلي ممنون بابت آموزش اين نكات جالب ... لطفا ادامه بديد استفاده ميكنيم .

باتشكر
نبي 8)
 

ariyahost

New Member
md5 !!!!

يه راه خوب :

اگر شما يه كاري مثل اين بكنيد :

SELECT * FROM `pws_users` WHERE 1 AND `user_userpass` = md5('test'); AND ...

منظورم اينه كه اين رو اجرا كنيد.اونوقت چطور ؟
:wink:
 

amozesh

Member
با سلام
آقا اميدك شما هم در مورد .net بگو ما بيشتر بدونيم
در مورد اون مطا لبي هم كه گفتيد راستش من مبتدي هستم اگه يك كم بيشتر توضيح بدين ممنون مي شم
در مورد انتقال اطلاعات مهم هم نگفتيد از چه راهي استفاده كنيم
از بقيه دوستان هم خيلي ممنون
 

جدیدترین ارسال ها

بالا