SQL 注入是一种攻击方式,在这种攻击方式中,恶意代码被插入到字符串中,然后将该字符串传递到 SQL Server 的实例以进行分析和执行。任何构成 SQL 语句的过程都应进行注入漏洞检查。常用的防止SQL注入的方法有:输入数据约束、使用存储过程、数据库的权限设置等都可以有效防止SQL注入。
(1)验证输入数据
可以在客户端使用Javascript进行验证,采用Javascript验证可以对数据进行简单的数据类型、长度、范围、格式验证。
在某些情况下可能避过客户端的验证,攻击者完全有可能获得网页的源代码,修改验证合法性的脚本(或者直接删除脚本),然后将非法内容通过修改后的表单提交给服务器。因此,要保证验证操作确实已经执行,唯一的办法就是在服务器端也执行验证。服务器端的验证可以使用服务器验证控件,也可以在CS文件中用Regex类进行验证,如:
if (Regex.IsMatch(Request.Cookies["SSN"], "^/d{3}-/d{2}-/d{4}$")) { // access the database } else { // handle the bad input }在验证时根据情况,拒绝包含以下字符的输入
输入字符
在 Transact-SQL 中的含义
;
查询分隔符。
'
字符数据字符串分隔符。
--
注释分隔符。
/* ... */
注释分隔符。服务器不对 /* 和 */ 之间的注释进行处理。
Xp_
用于目录扩展存储过程的名称的开头,如 xp_cmdshell。
(2)使用参数化输入的存储过程
SQL Server 中的 Parameters 集合提供了类型检查和长度验证。如果使用 Parameters 集合,则输入将被视为文字值而不是可执行代码。使用 Parameters 集合的另一个好处是可以强制执行类型和长度检查。范围以外的值将触发异常。以下代码段显示了如何使用 Parameters 集合
SqlDataAdapter myCommand = new SqlDataAdapter("AuthorLogin", conn);
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
SqlParameter parm = myCommand.SelectCommand.Parameters.Add("@au_id",
SqlDbType.VarChar, 11);
parm.Value = Login.Text;
当在存储过程中使用动态SQL时最好使用EXEC sp_executesql执行动态SQL如:
CREATE PROCEDURE InsertSales
@PrmOrderID INT,
@PrmCustomerID INT,
@PrmOrderDate DATETIME,
@PrmDeliveryDate DATETIME
AS
DECLARE @InsertString NVARCHAR(500)
DECLARE @OrderMonth INT
SET @InsertString = 'INSERT INTO ' +
SUBSTRING( DATENAME(mm, @PrmOrderDate), 1, 3) +
CAST(DATEPART(yy, @PrmOrderDate) AS CHAR(4) ) +
'Sales' +
' VALUES (@InsOrderID, @InsCustID, @InsOrdDate,' +
' @InsOrdMonth, @InsDelDate)'
SET @OrderMonth = DATEPART(mm, @PrmOrderDate)
EXEC sp_executesql @InsertString,
N'@InsOrderID INT, @InsCustID INT, @InsOrdDate DATETIME,
@InsOrdMonth INT, @InsDelDate DATETIME',
@PrmOrderID, @PrmCustomerID, @PrmOrderDate,
@OrderMonth, @PrmDeliveryDate
GO
(3)数据库权限设置
对于用来执行查询的数据库帐户,限制其权限。用不同的用户帐户执行查询、插入、更新、删除操作。由于隔离了不同帐户可执行的操作,因而也就防止了原本用于执行SELECT命令的地方却被用于执行INSERT、UPDATE或DELETE命令。
(4)对关键数据加密
将用户登录名称、密码等数据加密保存。加密用户输入的数据,然后再将它与数据库中保存的数据比较,这相当于对用户输入的数据进行了“消毒”处理,用户输入的数据不再对数据库有任何特殊的意义,从而也就防止了攻击者注入SQL命令。