SQL Injection
بسم الله الرحمن الرحیم
SQL Injection
در این آموزش قصد داریم در خصوص امنیت در SQL Server به صورت مختصر صحبت کنیم.
معمولا بیشتر مشتریان نگران امنیت اطلاعاتشان هستند و از تدابیری برای جلوگیری از SQL Injection صحبت می کنند. بیشتر اتفاقاتی که در خصوص SQL Injection رخ می دهد به دلیل مشکلاتی است که در SQL Server توسط طراحان پایگاه داده و برنامه نویسان انجام می شود، زیرا بیشتر طراحان اطلاعات کافی در خصوص SQL Injection ندارند و تنها نام آن را شنیده اند.
منظور از طراحان، کسانی هستند که پایگاه داده را طراحی و مدیریت می کنند که به اصطلاح به آنها DBA و یا Database Administrator گفته می شود.
SQL Injection نتیجه یک کد نویسی اشتباه است. یکی از شایع ترین دلایل وقوع SQL Injection استفاده از dynamic SQL است، بدین معنا که شما Query خود را به صورت داینامیک با استفاده از پارارمترهای ارسال شده کاربر اجرا کنید.
در این جا یک مثال ساده را بیان کرده ایم که کاربر می تواند با استفاده از ارسال پارامترهای First Name وLast Name یک Query ساده را اجرا کند.
کد خود را در یک Procedure به صورت زیر تعریف می کنیم.
USE AdventureWorks2014
GO
CREATE PROCEDURE search_first_or_last
@firstName NVARCHAR(50)
,@lastName NVARCHAR(50)
AS
BEGIN
DECLARE @sql NVARCHAR(4000)
SELECT @sql = ' SELECT FirstName ,MiddleName, LastName' +
' FROM Person.Person WHERE 1 = 1 '
IF @firstName IS NOT NULL
SELECT @sql = @sql + ' AND FirstName LIKE ''' + @firstName + ''''
IF @lastName IS NOT NULL
SELECT @sql = @sql + ' AND LastName LIKE ''' + @lastName + ''''
EXEC (@sql)
END
توضیح کد:
کد بالا بسیار ساده است، ما یک Procedure نوشته ایم، تا با ارسال دو پارامتر firstName و lastName اطلاعات افراد درخواستی را برای ما بازیابی کند.
تنها نکته ای که در این جا وجود دارد این است که ما برای انجام این کار پارامترها را به صورت جمع رشته ای در SQL Server ایجاد کرده ایم
@sql = @sql + ' AND FirstName LIKE ''' + @firstName + ''''
این کار باعث تا کاربر بتواند به سادگی دستور SQL خود را بر روی دیتابیس اجرا کند
اگر من Procedure خود را به صورت زیر اجرا کنم، چه اتفاقی خواهد افتاد؟
EXEC search_first_or_last '%K%', ''';drop table t1--'
خروجی عبارتی که توسط Procedure ما اجرا خواهد شد، به صورت زیر است.
SELECT FirstName, MiddleName, LastName FROM Person.Person WHERE 1 = 1 AND FirstName LIKE '%K%' AND LastName LIKE '';
DROP TABLE t1--'
همانطور که مشاهده می کنید ما به جای ارسال پارامتر دستور SQL ارسال کردیم. به این کار SQL Injection گفته می شود. در بسیاری از وب سایت ها اگر شما پارامتر خود را به SQL به صورت بالا ارسال کنید مشاده می کنید که می توانید آسیب سنگینی را به دیتابیس وب سایت مربوطه وارد نمایید. اما خواهشا هیچگاه این کار را انجام ندهید و به جای آن به مدیر وب سایت این خطا را گزارش کنید تا آنها مشکلشان را بر طرف نمایند.
اگر در برنامه خود (سی شارپ و یا زبان های برنامه نویسی دیگر) از ORM ها استفاده نمی کنید بهتر است به جای ارسال پارامتر ها به صورت String آنها را با استفاده از دستور command.Parameters به Procedure خود انتقال دهید.مثال:
SqlCommand command = new SqlCommand(commandText, connection);
command.Parameters.AddWithValue("@ID",customerID)
.....
یکی از مزایای Procedure رفع مشکل SQL Injection است اما به شرطی که پارامتر ها به صورت بالا برای SQL ارسال شود.
به سراغ مثال اصلی این آموزش بر می گردیم. طبیعتا مشکل را متوجه شده اید، کاربر می تواند به سادگی با استفاده از ارسال یک دستور ساده در Query ما Table ما را حذف نماید.
یکی از روش های حل ساده این مشکل استفاده از دستور sp_executesql می باشد.
CREATE PROCEDURE search_first_or_last
@firstName NVARCHAR(50)
,@lastName NVARCHAR(50)
AS
BEGIN
DECLARE @sql NVARCHAR(4000)
SELECT @sql = ' SELECT FirstName , MiddleName, LastName' +
' FROM Person.Person WHERE 1 = 1 '
IF @firstName IS NOT NULL
SELECT @sql = @sql + ' AND FirstName LIKE @firstName'
IF @lastName IS NOT NULL
SELECT @sql = @sql + ' AND LastName LIKE @lastName '
EXEC sp_executesql @sql
,N'@firstName nvarchar(50), @lastName nvarchar(50)'
,@firstName
,@lastName
END
با استفاده از دستور sp_executesql مقادیر ورودی کاربر را در پارامتر های خود قرار دادیم و درنهایت کد خود را اجرا کردیم.
پس اگر در برنامه خود از روش ارسال پارامتر به صورت SQL Parameter استفاده کنیم و همچنین Store Procedure خود را به روش بالا مقدار دهی و اجرا کنیم، می توانیم یکی از دلایل اصلی هک شدن وب سایت را از بین ببریم.
نیازی نیست که به دنبال کدهای پیچیده و روش های پیچیده باشید، همانطور که مشاهده کردید با یک خط کد ساده می توان بسیاری از مشکلات برنامه ها را حل نمود، اما این کار مستلزم مطالعه و بررسی ابزارها و روش ها است، از همین رو سعی خواهیم کرد با ارائه مطالب کوتاه و کاربردی مشکلات را حل نماییم.
خوشبختانه امروزه به دلیل استفاده از ORM ها (مانند Entity Framework و NHibernate) در زبان های برنامه نویسی بسیاری از خطاهای برنامه نویسان به صورت ناخودآگاه حدف می شود، زیرا این ORM ها هستند که کد شما را به SQL Server انتقال می دهند، از همین رو مشکلات برنامه نویسان کمتر باعث آسیب پذیر شدن سیستم ها می شود.
همچنین با توجه به استفاده از LINQ به جای رابطه مستقیم با پایگاه های داده ها، برخی از مشکلات دیگر نیز حل می شوند. در واقعه در گذشته برنامه نویسان مستقیما با SQL در ارتباط بوده اند و می توانستند ناخواسته ضعف های امنیتی در پایگاه داده خود ایجاد کنند. اما امروز قرار گیری دو لایه ORM و LINQ درصد خطاها را بسیار کاهش داده است.