PDA

View Full Version : چند سوال در مورد SQL Injection



fereshte22
شنبه 29 اردیبهشت 1386, 15:34 عصر
سلام
من مدتیه که بر روی یک پروژه کار میکنم..راستش تا حالا زیاد در مورد رعایت نکات امنیتی در پروژه ام فکر نکرده بودم.(این اولین پروژه جدیه من است)ولی در یکی از تاپیک ها یکی از دوستان در مورد یکی از کدهایم نکته ای را متذکر شدکه مشکل امنیتی دارد و مستعد برای SQL Injection است.به خاط همین من چندین تاپیک را برای جلوگیری از SQL Injection خوندم.در این تاپیک ها اکثرا دوستان گفته بودند که باید از sp استفاده کنیم.از اونجایی که من کدهای برنامه ام را بدون استفاده از sp نوشته ام میخواستم بدونم که ایا راه حلی برای فیلترینگ این کدها وجود ندارد که من مجبور نباشم اونها را تغییر بدهم.
من کدهام را به صورت زیر نوشته ام.
insert


insertsql = "insert into kala(name,tosif)"
insertsql &= "values('" & TextBox2.Text & "','" & TextBox1.Text & "')"


select برای چک کردن صحیح بودن نام کاربر ویا موارد دیگر


"select *from kala where name='" & TextBox1.Text & "'"

و کلا کدهام همین روال بالا را دارد.
در ضمن من فقط از مقدار integer برای انتقال اطلاعات بین صفحات استفاده میکنم.ایا این کار برای جلوگیری از SQL Injection کافی است؟
چند تا سوال دیگر هم دارم که ترجیح میدهم اول ابهاماتم در موارد بالا برطرف شود و بعد مطرح کنم.
دوستان اگر لطف کنند و راهنمایی کنند خیلی ممنون میشوم چون خیلی دچار تردیدشده ام.

iekrang
شنبه 29 اردیبهشت 1386, 15:53 عصر
To protect your application from SQL injection, perform the following steps
Step 1. Constrain input.
Step 2. Use parameters with stored procedures.
Step 3. Use parameters with dynamic SQL.

به نظر من الان بهترین کاری که میتونی انجام بدی از پارامترها استفاده کنی:

using System.Data;
using System.Data.SqlClient;

using (SqlConnection connection = new SqlConnection(connectionString))
{
DataSet userDataset = new DataSet();
SqlDataAdapter myCommand = new SqlDataAdapter(
"LoginStoredProcedure", connection);
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
myCommand.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11);
myCommand.SelectCommand.Parameters["@au_id"].Value = SSN.Text;

myCommand.Fill(userDataset);
}

Source: http://msdn2.microsoft.com/en-us/library/ms998271.aspx
در ضمن همینجا اگه سرچ کنی تاپیکهای مفیدی پیدا میکنی.
موفق باشی.

ealireza
شنبه 29 اردیبهشت 1386, 15:54 عصر
سلام
من مدتیه که بر روی یک پروژه کار میکنم..راستش تا حالا زیاد در مورد رعایت نکات امنیتی در پروژه ام فکر نکرده بودم.(این اولین پروژه جدیه من است)ولی در یکی از تاپیک ها یکی از دوستان در مورد یکی از کدهایم نکته ای را متذکر شدکه مشکل امنیتی دارد و مستعد برای SQL Injection است.به خاط همین من چندین تاپیک را برای جلوگیری از SQL Injection خوندم.در این تاپیک ها اکثرا دوستان گفته بودند که باید از sp استفاده کنیم.از اونجایی که من کدهای برنامه ام را بدون استفاده از sp نوشته ام میخواستم بدونم که ایا راه حلی برای فیلترینگ این کدها وجود ندارد که من مجبور نباشم اونها را تغییر بدهم.
من کدهام را به صورت زیر نوشته ام.
insert


insertsql = "insert into kala(name,tosif)"
insertsql &= "values('" & TextBox2.Text & "','" & TextBox1.Text & "')"


select برای چک کردن صحیح بودن نام کاربر ویا موارد دیگر


"select *from kala where name='" & TextBox1.Text & "'"

و کلا کدهام همین روال بالا را دارد.
در ضمن من فقط از مقدار integer برای انتقال اطلاعات بین صفحات استفاده میکنم.ایا این کار برای جلوگیری از SQL Injection کافی است؟
چند تا سوال دیگر هم دارم که ترجیح میدهم اول ابهاماتم در موارد بالا برطرف شود و بعد مطرح کنم.
دوستان اگر لطف کنند و راهنمایی کنند خیلی ممنون میشوم چون خیلی دچار تردیدشده ام.
دوست من
بهترین راه استفاده از Parameter هست .
نیازی هم به SP نیست !!!

یک راه دیگه هم وجود داره که


"
'

رو با کد اسکیشون replace کنی و در جاهایی که INT رو لازم داری فقط عدد باید به SQL منتقل شه


بازم تاکید میکنم بهترین کار همون Parameters هست
خیلی هم راحت هست

موفق باشید

javad3151
یک شنبه 30 اردیبهشت 1386, 07:05 صبح
استفاده از پارامتر مشکل رو حل نمیکنه ، شما میتونید یک تابع درست کنید و تمام کدهایی رو که ممکنه مشکل ایجاد کنه را Replace کنی ؛ من خودم این تابع رو نوشتم و فکر کنم کامل باشه:


Public Function secure(ByVal a As String) As String
a = Replace(a, "'", "ٰٰٰٰ ٰ")
a = Replace(a, "script", "BLOCKED")
a = Replace(a, "/*", " ")
a = Replace(a, "*/", " ")
a = Replace(a, "xp_", " ")
a = Replace(a, "union", "_union")
a = Replace(a, "having", "_having")
a = Replace(a, "insert", "_insert")
a = Replace(a, "select", "_select")
a = Replace(a, "delete", "_delete")
a = Replace(a, "update", "_update")
a = Replace(a, "drop", "_drop")
a = Replace(a, "exec", "_exec")
a = Replace(a, "sp_", "_sp_")
a = Replace(a, "shutdown", "_shutdown")
a = Replace(a, "javascript\:", "BLOCKED ")
a = Replace(a, "vbscript\:", "BLOCKED ")

secure = a
Return secure
End Function

در مرحله بعد ، هر جا که میخواهید مقادیر را به دیتابیس بفرستید با استفاده از این تابع بفرستید:


"select * from...." & secure(textbox1.text

SalarSoft
یک شنبه 30 اردیبهشت 1386, 09:24 صبح
استفاده از پارامتر مشکل رو حل نمیکنه
دقیقا درسته ولی استفاده از StoreProcedure مشکل رو حل میکنه.

ولی خب برخی وقتا لازمه که query به صورت دینامیک ایجاد بشه که:
برای داده های char (یعنی رشته ای) با جایگزین کردن ' با دو تا مشکل حل میشه:




public string EncodeString(string sqlstring)
{
return sqlstring.Replace("'", "''");
}



برای داده ای غیر رشته ای همونطور که javad3151 گفت باید کاراکتر ها و عبارات غیر مجاز رو حذف کنید، البته اونیکه ایشون گفتند خلی سخت گیرانه است:


public static string SqlRemoveSeriousChar(string sqlstring)
{
string[] restrictedChars = new string[] { "\"", "'", ";", ",", "[", "]", "%", "*", "=" };
for (int i = 0; i < restrictedChars.Length; i++)
sqlstring = sqlstring.Replace(restrictedChars[i], "");
return sqlstring;
}

Vahid_moghaddam
یک شنبه 30 اردیبهشت 1386, 10:15 صبح
استفاده از روالهای مدفون (SPs) فقط به دلیل بالابردن امنیت نیست. مزایای دیگه ای هم داره مثل سرعت اجزای بالاتر. اما در هر پروژه ای ممکنه شرایطی پیش بیاید که مایل نباشید از SP ها استفاده کنید. همونطور که دوستان اشاره کردن، بهترین کار داشتن شناختی کلی از حمله هاییه که ممکنه به سایت شما صورت بگیره.
در مورد sql injection بهترین روش همونیه که اشاره شده. اما حمله ها محدود به این نمیشه. پیشنهاد می کنم، قسمت امنیت و کلاسهای امنیتی MSDN رو اگه نخوندین، بخونید یا در همین سایت جستجو کنید.
در هر حال، هیچ سایتی امن نیست!

Chabok
یک شنبه 30 اردیبهشت 1386, 10:38 صبح
سلام
ببخشید . اگر در کد بالا آمپولزن(تزریقگر) به جای shutdown بنویسه ShutDown چی میشه ؟
ایا تابع Replace نیز Case Sensitive میباشد ؟

fereshte22
یک شنبه 30 اردیبهشت 1386, 14:21 عصر
سلام
از همه دوستان که لطف کردند و راهنمایی کردند خیلی ممنون هستم.من اگرباز هم سوالی در این مورد داشتم در همین تاپیک مزاحم دوستان میشوم.
ممنون

fereshte22
یک شنبه 30 اردیبهشت 1386, 14:53 عصر
سلام
دوست عزیز javad3151 اول یه سوال داشتم و اون اینکه میشه توضیح دهید که چرا استفاده از پارامتر مشکل را حل نمیکند.؟این سوال را از این جهت پرسیدم که چند تا از دوستان روی پارامتر نظر داشتند.
در ضمن من تابع شما را به صورت زیر استفاده کردم.ایا منظورتون به همین صورت بود..


"select *from kala where name='" & secure(TextBox1.Text) & "'"

و یا برای insert


insertsql = "insert into kala(name,tosif)"
insertsql &= "values('" & secure(TextBox2.Text) & "','" & secure(TextBox1.Text) & "')"

ممنون

javad3151
یک شنبه 30 اردیبهشت 1386, 19:44 عصر
تزریق اسکریپت مختص query و sql نیست و هکر می تونه با استفاده از تزریق کدهای برنامه نویسی اقدام به هک برنامه کنه ، تابعی که من نوشتم کلیه موارد رو ساپورت میکنه
در پارامتردر 2 زمان مشکل پیش میاد:
1- وقتی کارکترری مثل ' داشته باشه که با تبدیل اون به '' مشکل حل میشه
2- وقتی شما query (معمولا بخشی از query) را به صورت پارامتر به SP ارسال کنید (پارامتر لزوما دربردارنده یه مقدار برای یک فیلد نیست بلکه ممکنه کل query شما که اون رو بصورت داینامیک ساخته اید رو بصورت پارامتر پاس کنید)

fereshte22
یک شنبه 30 اردیبهشت 1386, 21:27 عصر
دوست عزیز از راهنماییه شما ممنون هستم.فقط شما یک سوال من را جواب ندادید.
ایا من تابع را برای دستورات select وinsert درست استفاده کردم.؟

javad3151
دوشنبه 31 اردیبهشت 1386, 06:55 صبح
بله ، درسته
حتما این رو هم خودتون بهتر میدونید که بهتره تابع رو در یک Public Module قراربدید که از تمام صفحات و بخشهای برنامه قابل استفاده باشه

fereshte22
دوشنبه 31 اردیبهشت 1386, 15:56 عصر
سلام
ازراهنماییه شما بینهایت ممنون هستم
ببینید من یک کلاس با نام Class1.vb ایجاد کردم و در اون کد زیر را قرار دادم(البته تابع را اینجا کامل ننوشتم)


Imports Microsoft.VisualBasic
Public Class Class1
Public Function secure(ByVal a As String) As String
a = Replace(a, "'", "ٰٰٰٰ ٰ")

secure = a
Return secure
End Function
End Class

بعد در صفحات خود تابع را به صورت زیر فراخوانی کردم


Dim cs As Class1
cmdselect = New SqlCommand("Select * From keysearch Where keysearch= '" & cs.secure(javab) & "'", con)

ولی خطای زیر را میدهد.
Object reference not set to an instance of an object.
نمیدونم مشکلش چیه؟ایا تابع را در ست در کلاس تعریف نمیکنم ویا در فراخوانیه اون مشکل دارم؟

در ضمن یه سوال دیگه هم داشتم .در جزوه ای که اقای نصیری در همین سایت در مورد sql injection مطرح کرده بودن ";" و"--" را هم به عنوان کلمات خطرناک در نظر گرفته بودند.ویا مثلا دوستمون salarsoft در همین تاپیک چند کلمه دیگر را هم درتابعشون در نظر گرفته بودندایا در تابع secure نباید این کلمات را هم منظور کنیم؟
خیلی خیلی ممنون

MehranZand
دوشنبه 31 اردیبهشت 1386, 17:22 عصر
خط
Dim cs As Class1
به

Dim cs As New Class1
تغییر بده . کلاس رو باید در هنگام استفاده ازش یه new object بسازی

javad3151
سه شنبه 01 خرداد 1386, 10:05 صبح
من یک کلاس با نام Class1.vb ایجاد کردم و در اون کد زیر را قرار دادم
توی تاپیک قبلی گفتم که باید یه ماژول تعریف کنید نه یک کلاس! . به این صورت:


Public Module test
YOUR PUBLIC FUNCTION....
End Module

این روش خیلی آسونتره


";" و"--" را هم به عنوان کلمات خطرناک در نظر گرفته بودند
تابعی که نوشتم همه موارد را ساپورت میکنه و نیازی به این دو نیست

Chabok
سه شنبه 01 خرداد 1386, 11:29 صبح
سلام
من امتحان کردم و دیدم که تابع Replace به کوچک و بزرگ بودن حروف حساس می باشد
یعنی اگه کسی بجای insert کلمه ی INSERT را تزریق کند تابع آقای javad3151 اثری نمیکند

Chabok
پنج شنبه 03 خرداد 1386, 10:26 صبح
سلام
بیایید این بخش رو به یه جایی برسونیم

حالا که معلوم شد تابع Replace یه حروف کوچک و بزرگ حساسه بیایید یه کاری بکنیم

1.متن گرفته شده از کاربر رو بگیریم و به حروف کوچک ببریم toLowerCase
2.حالا بیاییم و کاراکترهای خطرناک رو حذف کنیم که بدوینم اگه وجود داشته باشه حذف خواهد شد (میخواد حروف کوچیک باشه یا بزرگ)
3.حالا تعداد کاراکترهای متن اولی رو با جدیده یعنی متن سالم مقایسه میکنیم
4.اگر تعداد کاراکترهای متن اولیه بیشتر از متن جدید بود مشخص میشه تزریق در حال انجام بوده
و دراین صورت میشه تعداد تزریق ها رو هم پیدا کرد . مثلا توی سایت نوشت 10 بار به سایت حمله شده است . یا چنین چیزی
5.و حالا اگه متن اول با متن بعدی تعداد کاراکترهاش یکی بود بیاییم و متن اصلی رو توی دیتابیس
بریزیم تا حروفی که کاربر بصورت بزرگ وارد کرده به هم نخورند و متن ورودی به هم نخوره .

ممنون . موفق و پیروز باشید . منتظر نظرات و پیشنهادات شما هستم

javad3151
پنج شنبه 10 خرداد 1386, 11:30 صبح
نسخه اصلاح شده تابع (البته توی این تابع مشکل حروف ی و ک فارسی هم حل شده):



Public Module Secure_Module
Public Function secure(ByVal a As String) As String
a = Replace(a.ToLower, "'", "ٰٰٰٰ ٰ")
a = Replace(a, ">", "_>")
a = Replace(a, "<", "<_")
a = Replace(a.ToLower, "/*", " ")
a = Replace(a.ToLower, "*/", " ")
a = Replace(a.ToLower, "xp_", " ")
a = Replace(a.ToLower, "union", "_union")
a = Replace(a.ToLower, "having", "_having")
a = Replace(a.ToLower, "insert", "_insert")
a = Replace(a.ToLower, "select", "_select")
a = Replace(a.ToLower, "delete", "_delete")
a = Replace(a.ToLower, "update", "_update")
a = Replace(a.ToLower, "drop", "_drop")
a = Replace(a.ToLower, "exec", "_exec")
a = Replace(a.ToLower, "sp_", "_sp_")
a = Replace(a.ToLower, "script", "BLOCKED")
a = Replace(a.ToLower, "shutdown", "_shutdown")
a = Replace(a.ToLower, "javascript\:", "BLOCKED ")
a = Replace(a.ToLower, "vbscript\:", "BLOCKED ")
a = Replace(a.ToLower, "ی", "ی")
a = Replace(a.ToLower, "ک", "ک")
a = Replace(a.ToLower, "ڪ", "ک")
secure = a
Return secure
End Function
End Module

با ساختن این ماژول ، در همه صفحات میتونید ازش براحتی استفاده کنید

fereshte22
دوشنبه 18 تیر 1386, 17:31 عصر
سلامخسته نباشید.یه سوال داشتم.من در دستور insert خود از تابع بالا استفاده کردم.و قبل از مقادیر textbox تابع بالا را قرار دادم.ولی فقط وقتی به طور اتفاقی مقدار textbox را خالی گذاشتم خطای زیر را میگیردObject reference not set to an instance of an object.میتونم بپرسم مشکل چیه؟

Behrouz_Rad
دوشنبه 18 تیر 1386, 17:37 عصر
خواهر با پشتکار من، از کدامین خط این خطا را دریافت می کنی؟

fereshte22
دوشنبه 18 تیر 1386, 18:11 عصر
سلام
از خط زیر خطا میگیرد.


a = Replace(a.ToLower, "/*", " ")

البته من از همون موقع که دوستمون javad3151 تابع را گذاشتند ازش استفاده میکنم و مشکلی نداشت ولی امروز در همین مورد که عرض کردم به مشکل برخوردم.

Behrouz_Rad
دوشنبه 18 تیر 1386, 18:18 عصر
البته مشخصه که دوستمون و یا دوستانی که این تابع رو نوشتند و پیشنهاد استفاده از اون رو دادند، اطلاعاتی چندانی در مورد راه های مقابله با SQL Injection ندارند.
SQL Injection با SP ها قابل جلوگیری هست.
در تابعی که دوستمون نوشتن، فرضا اگر بنده بخوام عبارتی با نام Drop رو در دیتابیس ذخیره کنم تکلیف چیه؟!!
آیا باید قید استفاده از کلماتی که احتمال به کار گیری Injection با اونها وجود داره رو زد؟


a = a.Replace("/*", " ")


عجیبه که بعد از چند وقت تازه با این مشکل برخورد کردی!
به هر حال استفاده از متد Replace کلاس String بهتر هست.

موفق باشید.

m.hamidreza
دوشنبه 18 تیر 1386, 18:49 عصر
البته مشخصه که دوستمون و یا دوستانی که این تابع رو نوشتند و پیشنهاد استفاده از اون رو دادند، اطلاعاتی چندانی در مورد راه های مقابله با SQL Injection ندارند.
SQL Injection با SP ها قابل جلوگیری هست.
در تابعی که دوستمون نوشتن، فرضا اگر بنده بخوام عبارتی با نام Drop رو در دیتابیس ذخیره کنم تکلیف چیه؟!!
آیا باید قید استفاده از کلماتی که احتمال به کار گیری Injection با اونها وجود داره رو زد؟


a = a.Replace("/*", " ")


عجیبه که بعد از چند وقت تازه با این مشکل برخورد کردی!
به هر حال استفاده از متد Replace کلاس String بهتر هست.

موفق باشید.

استاد لطفا از بحث بین علما یه نتیجه ای هم واسه فقرا بگیرید !

SP is enough ? or that function or use parameters or all of them ?

javad3151
دوشنبه 18 تیر 1386, 18:50 عصر
در تابعی که دوستمون نوشتن، فرضا اگر بنده بخوام عبارتی با نام Drop رو در دیتابیس ذخیره کنم تکلیف چیه؟!!

تابعی که من نوشتم برای استفاده در یک بانک اطلاعات دانشجویی هست که هیچوقت در اون از این قبیل دستورات استفاده نمیشه

SQL Injection با SP ها قابل جلوگیری هست.

من از این تابع فقط برایSQL Injection استفاده نکردم (مثلابرای یکسان سازی برخی کارکتر های فارسی هم استفاده می کنم )
تابعی که نوشتم را به این صورت اصلاح کردم:


PublicFunction secure(ByVal a AsString) AsString
If a = NothingOr a = ""ThenReturn a : ExitFunction
a = Trim(a)
a = Replace(a, "'", "ٰٰٰٰ ٰ")
a = Replace(a, ">", "_>")
a = Replace(a, "<", "<_")
'a = Replace(a, "_", "__")
a = Replace(a, "/*", " ")
a = Replace(a, "*/", " ")
a = Replace(a.ToLower, "script", "BLOCKED")
a = Replace(a.ToLower, "xp_", " ")
a = Replace(a.ToLower, "union", "_union")
a = Replace(a.ToLower, "having", "_having")
a = Replace(a.ToLower, "insert", "_insert")
a = Replace(a.ToLower, "select", "_select")
a = Replace(a.ToLower, "delete", "_delete")
a = Replace(a.ToLower, "update", "_update")
a = Replace(a.ToLower, "drop", "_drop")
a = Replace(a.ToLower, "exec", "_exec")
a = Replace(a.ToLower, "sp_", "_sp_")
a = Replace(a.ToLower, "shutdown", "_shutdown")
a = Replace(a.ToLower, "javascript\:", "BLOCKED ")
a = Replace(a.ToLower, "vbscript\:", "BLOCKED ")
a = Replace(a, "ی", "ی")
a = Replace(a, "ک", "ک")
a = Replace(a, "ڪ", "ک")
a = Replace(a, "۱", "1")
a = Replace(a, "۲", "2")
a = Replace(a, "۳", "3")
a = Replace(a, "۴", "4")
a = Replace(a, "۵", "5")
a = Replace(a, "۶", "6")
a = Replace(a, "۷", "7")
a = Replace(a, "۸", "8")
a = Replace(a, "۹", "9")
a = Replace(a, "۰", "0")
secure = a
Return secure
EndFunction

Behrouz_Rad
سه شنبه 19 تیر 1386, 00:08 صبح
تابعی که من نوشتم برای استفاده در یک بانک اطلاعات دانشجویی هست که هیچوقت در اون از این قبیل دستورات استفاده نمیشه
هیچ وقت؟ این حرف اشتباست! 1 درصد احتمال بده که من بخوام به هر دلیلی Insert رو در دیتابیس قرار بدم! تکلیفم چیه؟ تو که از داده های ارسالی خبر نداری!
فرض کن من یک کاربر خنگم و Insert رو وارد می کنم!
در ضمن، این درست نیست که برای هر کاربرد یک تابع خاص ایجاد کرد (هر چند که در این مورد اصولا نیازی به 2 تا تابع مختلف نیست!)
همچنین آیا فکر می کنی دستورات Injection به همین تعداد اندک دستوری که نوشتی محدود میشه؟!
یکی از دستورات میتونه این باشه:


admin' or 1=1 --

من با ورودی بالا تا حالا چندین سایت رو هک کردم...!
نمیشه برای تمامی حالات Injection دستور بنویسی!

من از این تابع فقط برایSQL Injection استفاده نکردم (مثلابرای یکسان سازی برخی کارکتر های فارسی هم استفاده می کنم )
تابعی که نوشتم را به این صورت اصلاح کردم:
برای یکسان سازی کاراکترهای فارسی بله اما برای جلوگیری از SQL Injection هرگز!

موفق باشید.

javad3151
سه شنبه 19 تیر 1386, 07:16 صبح
تو که از داده های ارسالی خبر نداری!

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

یکی از دستورات میتونه این باشه:

کد:
admin' or 1=1 --
من با ورودی بالا تا حالا چندین سایت رو هک کردم...!

در تابعی که نوشتم دستور بالا کار نمیکنه چون کارکتر ' تبدیل به یک کارکتر یونیک مشابه میشه که در sql server معنی نداره

برای یکسان سازی کاراکترهای فارسی بله اما برای جلوگیری از SQL Injection هرگز!

میشه بفرمایید با وجود تابع فوق چطور میتونید با استفاده از SQL Injection سایت رو هک کنید!

من یک کاربر خنگم و Insert رو وارد می کنم!

هنوز نگفتید که با این نوع کاربران چطور برخورد کنیم

Nightbat
سه شنبه 19 تیر 1386, 16:11 عصر
اتفاقا چون خبر دارم این کار رو کردم، اگر برنامه نویس از نوع داده های دیتابیسش اطلاع نداشته باشه که والسلام

چطور می تونید مطمئن باشید کاربر چی وارد می کنه ؟!؟!؟؟:متفکر:

Behrouz_Rad
سه شنبه 19 تیر 1386, 16:18 عصر
اتفاقا چون خبر دارم این کار رو کردم، اگر برنامه نویس از نوع داده های دیتابیسش اطلاع نداشته باشه که والسلام
همه افراد مثل شما از علوم غیبه بهره مند نیستند!

این یک مسئله ی کاملا روشن و واضحه و واقعا نمیدونم که چرا بر صحیح بودن تابعی که نوشتی اینقدر تاکید داری!
اصل مطلب اینه:
تو داری داده های ورودی رو فیلتر می کنی! یعنی داده ها رو دستکاری می کنی و مانع از ارسال کاراکترهایی میشی که کاربر ممکنه دوست داشته باشه از اونها استفاده کنه!
اصلا چرا راه دوری بریم؟!
فرض کن در همون سیستم دانشجویی که مثال زدی، قسمتی برای وارد کردن نام کاربری وجود داره و من دلم میخواد که نام کاربریم Delete یا Union Man باشه. در این صورت چکار باید بکنم؟

در تابعی که نوشتم دستور بالا کار نمیکنه چون کارکتر ' تبدیل به یک کارکتر یونیک مشابه میشه که در sql server معنی نداره
اون تنها یک مثال بود برای اینکه بدونی SQL Injection تنها به حالاتی که نوشتی محدود نمیشه!

میشه بفرمایید با وجود تابع فوق چطور میتونید با استفاده از SQL Injection سایت رو هک کنید!
اینجا جایی برای اثبات قابلیت های امثال من نیست اما...
فرضا اگر دستور SQL من به شکل زیر باشه،


SELECT fieldlist
FROM table
WHERE id = 22 ;

تابع تو چه کاری میتونه در مقابل تزریق زیر انجام بده؟


SELECT fieldlist
FROM table
WHERE id = 22 OR 1=1;


موفق باشید.

javad3151
سه شنبه 19 تیر 1386, 18:31 عصر
اینجا جایی برای اثبات قابلیت های امثال من نیست اما...

جناب آقای راد،اینجا نه من و نه هیچ کس دیگه ادعایی نداره و این بحث هم یک بحث علمیه
خود من شخصا از جنابعالی مطالب زیادی یادگرفتم و شما جای استاد من هستید

تابع تو چه کاری میتونه در مقابل تزریق زیر انجام بده؟

کد:
SELECT fieldlist FROM table WHERE id = 22 OR 1=1;

مطمئنا نوع داده های ورودی کاربر چک میشه و جایی که باید مقدار عددی وارد کنه نمیتونه مقدار متنی وارد کنه!

اون تنها یک مثال بود برای اینکه بدونی SQL Injection تنها به حالاتی که نوشتی محدود نمیشه!

اتفاقا من هم منتظر یک مثال هستم که ببینم کجای کار رو اشتباه میکنم ، ولی هر دو مثالی که زدی نمیتونه برنامه رو هک کنه!

فرض کن در همون سیستم دانشجویی که مثال زدی، قسمتی برای وارد کردن نام کاربری وجود داره و من دلم میخواد که نام کاربریم Delete یا Union Man باشه. در این صورت چکار باید بکنم؟

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

Behrouz_Rad
سه شنبه 19 تیر 1386, 18:47 عصر
مطمئنا نوع داده های ورودی کاربر چک میشه و جایی که باید مقدار عددی وارد کنه نمیتونه مقدار متنی وارد کنه!
عجب!
برادر من شما فرض کن من یک فیلد عددی دارم! چرا به بیراهه میری؟!!!

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

ثانیا نمیدونم چرا راه حل مورد نظرتون رو ارائه نمیکنید ؟!
راه حل رو در پست 22 ارائه دادم و عرض کردم:

SQL Injection با SP ها قابل جلوگیری هست.

موفق باشید.

javad3151
چهارشنبه 20 تیر 1386, 07:56 صبح
نقل قول:
مطمئنا نوع داده های ورودی کاربر چک میشه و جایی که باید مقدار عددی وارد کنه نمیتونه مقدار متنی وارد کنه!
عجب!
برادر من شما فرض کن من یک فیلد عددی دارم! چرا به بیراهه میری؟!!!

یعنی شما نوع داده های ورودی رو چک نمیکنید ؟ حتما اونهایی هم که چک میکنند به بیراهه میرند!!

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


راه حل رو در پست 22 ارائه دادم و عرض کردم:

نقل قول:
SQL Injection با SP ها قابل جلوگیری هست.

اگر بخواهید برای تهیه یک گزارش پیچیده، sql رو دستی تهیه کنید چی؟ به عنوان مثال من خودم چنین کاری توی برنامه انجام میدم، در بخش گزارشگیری ، یوزر میتونه با استفاده از تمامی فیلدها و AND OR () LIKE و... هر نوع گزارشی رو تهیه کنه

Behrouz_Rad
چهارشنبه 20 تیر 1386, 09:48 صبح
یعنی شما نوع داده های ورودی رو چک نمیکنید ؟ حتما اونهایی هم که چک میکنند به بیراهه میرند!!

نه ، هنوز نگفتی چطور میتونی با وجود این تابع برنامه رو هک کنی(با اینکه به گفته شما من و سایر دوستان هیچی از SQL Injection نمی فهمیم ولی شما....)

متاسفانه نمیدونم چرا از قضیه خودت رو دور می کنی!
کد تو مشکلش اینه که داده های ورودی رو دستکاری می کنه و در مقابل فیلدهای عددی نیز هیچ کاری نمی تونه انجام بده.

اگر بخواهید برای تهیه یک گزارش پیچیده، sql رو دستی تهیه کنید چی؟ به عنوان مثال من خودم چنین کاری توی برنامه انجام میدم، در بخش گزارشگیری ، یوزر میتونه با استفاده از تمامی فیلدها و AND OR () LIKE و... هر نوع گزارشی رو تهیه کنه
به راحتی!
به این کار استفاده از Dynamic SQL میگن.
کوئری خودت رو در یک SP ایجاد می کنی و در اون SP از SP سیستمی sp_executesql استفاده کن و کوئری خودت رو به اون پاس بده:


sp_executesql @SQLString


موفق باشید.

javad3151
چهارشنبه 20 تیر 1386, 14:14 عصر
به این کار استفاده از Dynamic SQL میگن.
کوئری خودت رو در یک SP ایجاد می کنی و در اون SP از SP سیستمی sp_executesql استفاده کن و کوئری خودت رو به اون پاس بده:

کد:
sp_executesql @SQLString

شاید من منظورم رو خوب نرسوندم !!
شما یک دستورsql بصورت دستی درست میکنید، مطمئنا باید هنگام ساختن این دستور طوری عمل کنید که کاربر نتونه دستورات دیگری مثل Admin' or 1=1 یا... رو اضافه کنه ، چون در غیر این صورت براحتی میتونه سایت رو هک کنه
SP که نمیتونه بفهمه که کدوم قسمت از دستور رو شما نوشتید و کدوم رو هکر!!!

Behrouz_Rad
چهارشنبه 20 تیر 1386, 14:19 عصر
SP که نمیتونه بفهمه که کدوم قسمت از دستور رو شما نوشتید و کدوم رو هکر!!!
تو برنامه ای نوشتی که در اون اجازه میدی کاربر دستور SQL رو مستقیما وارد کنه و این دستور رو به عنوان Command به SQL Server میفرستی؟!!!
این طرز برنامه نویسی از کجا نشات گرفته؟!

javad3151
چهارشنبه 20 تیر 1386, 18:17 عصر
تو برنامه ای نوشتی که در اون اجازه میدی کاربر دستور SQL رو مستقیما وارد کنه و این دستور رو به عنوان Command به SQL Server میفرستی؟!!!
این طرز برنامه نویسی از کجا نشات گرفته؟!
اگر شما رو نمی شناختم ، فکر میکردم تازه چند ماهه که برنامه نویسی رو شروع کردی(:

در برنامه من اطلاعات در 160 فیلد اصلی ذخیره میشه (در کل برنامه حدود 60 جدول داره) ، من بخشی رو طراحی کردم که کاربر میتونه بر اساس تمام این فیلدها، بصورت نامحدود ،تمامی شروط دلخواه رو بصورت فارسی(نه دستورات مستقیم sql) اعمال کرده و حتی نتایج گزارش رو در جدولی که خودش طراحی کرده ببینه.
مثلا کاربر میگه: تمام دانشجویانی که تاریخ تولد آنها بعد از 1355 باشه و کتابی تالیف کرده باشه و( آدرس ایمیل آنها موجود باشه یا آدرس پستی موجود باشه) و....

یه گزارشگیری خفن داینامیک.
مطمئنا در این حالت هیچ راهی ندارید جز اینکه : 1- نوع داده های ورودی را چک کنید 2- داده های ورودی را فیلتر کنید

Behrouz_Rad
چهارشنبه 20 تیر 1386, 19:46 عصر
یک Screenshot از این قسمت برنامه قرار بده.

javad3151
چهارشنبه 20 تیر 1386, 21:54 عصر
فایل ضمیمه رو نگاه کنید
هرچند که خیلی از زوایای برنامه در یک تصویر قابل درک نیست ، مثلا اگر کاربر یک فیلد Bit انتخاب کنه ، فقط میتونه از یک لیست بلی/دارد یا خیر/ندارد را انتخاب کنه، و یا فیلد های خاص دیگه ای که مقدارش رو فقط از لیست میتونه انتخاب کنه

Behrouz_Rad
چهارشنبه 20 تیر 1386, 22:52 عصر
تو دقیقا می تونی دستورات همین محیط رو در یک SP که شرحش رو در پست 32 دادم ایجاد کنی.
در مورد استفاده از sp_executesql به شکل پارامتریک که در پست 32 اشاره کردم مطالعه کن.

موفق باشید.

javad3151
پنج شنبه 21 تیر 1386, 06:53 صبح
تو دقیقا می تونی دستورات همین محیط رو در یک SP که شرحش رو در پست 32 دادم ایجاد کنی.

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

در هرصورت مباحث هک خیلی زیاده( SQL injection, Cross site scripting, google hacking ,...) که فکر کنم SQL injection از موارد قدیمی باشه و بیشتر برنامه نویس ها براحتی میتونند با اون به مقابله بپردازند و بهتره که انرژی مون رو صرف موارد جدید بکنیم

Behrouz_Rad
پنج شنبه 21 تیر 1386, 09:53 صبح
در هرصورت مباحث هک خیلی زیاده( SQL injection, Cross site scripting, google hacking ,...) که فکر کنم SQL injection از موارد قدیمی باشه و بیشتر برنامه نویس ها براحتی میتونند با اون به مقابله بپردازند و بهتره که انرژی مون رو صرف موارد جدید بکنیم

خیر!
اتفاقا همین چند روز پیش بود که سایت انگلیسیه مایکروسافت به روش SQL Injection هک شد!

به جون بهروز خودت هم متوجه شدی که هنگام ساخت این دستورات باید حتما داده های ورودی رو فیلتر کنی و بعدا از طریق SP اجراش کنی وگرنه براحتی سیستمت هک میشه
به هیچ وجه اینجور نیست!
این حرف تو نشون میده که اصلا دنبال مستندات sp_executesql نرفتی!
یک نمونه از این شکل اسکریپت نویسی رو واست قرار میدم تا متوجه اصل قضیه بشی:



CREATE PROCEDURE spDynamicSearch
(@Relationship varchar(9) = NULL
,@City nvarchar(30) = NULL
,@CompanyName nvarchar(80) = NULL
,@ContactName nvarchar(60) = NULL
,@Debug bit = 0)
AS
BEGIN
DECLARE @SQL nvarchar(4000), @WhereClause nvarchar(500)
SET @SQL = N'SELECT City, CompanyName, ContactName,
Relationship FROM "Customer AND Suppliers BY City"'
SET @WhereClause = N' WHERE 1=1'
IF @Relationship IS NOT NULL
SET @WhereClause = @WhereClause + ' AND RelationShip =
@Relationship$'
IF @City IS NOT NULL
SET @WhereClause = @WhereClause + ' AND City LIKE @City$'
IF @CompanyName IS NOT NULL
SET @WhereClause = @WhereClause + ' AND CompanyName LIKE
@CompanyName$'
IF @ContactName IS NOT NULL
SET @WhereClause = @WhereClause + ' AND ContactName LIKE
@ContactName$'
SET @SQL = @SQL + @WhereClause
IF @Debug = 1
PRINT @SQL
EXEC sp_executesql
@SQL,
N'@RelationShip$ varchar(9), @City$ nvarchar(30),
@CompanyName$ nvarchar(80), @ContactName$ nvarchar(60)',
@RelationShip$ = @RelationShip,
@City$ = @City,
@CompanyName$ = @CompanyName,
@ContactName$ = @ContactName
END
GO

به اسکریپت فوق دقت کن و ببین که کلاس WHERE به چه شکل ساخته شده.
کلاس های دیگه هم به همین شکل میتونن پیاده سازی بشن.

بحث رو جمع بندی می کنیم...
تابعی که در پست 24 گذاشتی به هیچ وجه تابع مناسبی برای جلوگیری از SQL Injection نیست.
این تابع تنها بر روی مقادیر رشته ای کاربرد داره و نه بر روی مقادیر عددی اما به چه قیمتی؟
در هر دو حالت شما داده های ورودی کاربر رو فیلتر میکنی و اگر کاربر کلماتی رو به عنوان ورودی به سیستم بده که این کلمات جزء دستورات SQL هستند، توفیقی در نتیجه ی کارش حاصل نخواهد شد.
همچنین، در این حالت استفاده از SP نیز ممکن نیست چون شما دستور SQL رو به صورت RunTime اجرا می کنید و نه Precompiled.
حتما میدونی که تنها یکی از دلایل استفاده از SP جلوگیری از SQL Injection هست و Execute Plan ای که برای SP به دست میاد درصد زیادی از سربار بر روی سرور رو کاهش میده.
همچنین SP ها کد SQL رو از کد برنامه جدا می کنند و در این حالت تغییرات آتی در برنامه به راحتی امکان پذیره.
در نهایت به هر شکلی که بخوای عمل کنی، میتونی از Dynamic SQL در کنار SP ها بهره ببری و از خطرات SQL Injection در امان باشی.

با سپاس فراوان از شما برای شرکت در این بحث و تمامی دوستانی که این مطلب رو دنبال کردند.

موفق باشید.