一、问题
代码:string sql = "select * from client where name='"+name+"'";
变量name是由用户提供的;
如果用户输入:Blake' or 1=1--
那么sql语句为:select * from client where name='Blake' or 1=1--'
返回结果将是表client中的所有信息。
二、伪补救措施一:将引号转义
name = name.Replace("'","''");
试图将单引号转义,从而消除攻击,生成无效的SQL语句,但是对于非字符串的字段值有用,并不代表对其他字段值也有用,比如:
"where age="+age;
输入:35 shutdown将导致服务器关闭;
此外,高深的攻击者也可用char(0x27)来使用单引号:
declare @a char(20) select @a=0x73687574646f776e exec(@a)
这个构造实际上是调用shutdown命令,十六进制串就是shutdown的ASCII的等价形式。
三、伪补救措施二:使用存储过程
许多人相信调用存储过程会让应用程序免受SQL注入攻击,其实是错误的。
这样做只会阻止某些类型的攻击。
string name=...;
sqlstring = @"exec sp_GetName '"+name +"'";
试图输入:Blake' or 1=1-- 将会失败,因为不能通过存储过程调用一次连接。
但是进行数据操作却是完全合法的:
exec sp_GetName 'Blake' insert into client values(1005)--'
四、补救措施:
1、永远不要以sysadmin身份连接数据库,因为这样对于开发人员来说运行良好,对攻击者来说也如此;
2、以安全的方式创建SQL语句:参数化查询比代码中手工创建SQL速度更快更安全;
3、以安全的方式创建SQL存储过程:为对象名称使用quotename函数,其次,使用sp_executesql执行
动态创建的SQL语句;
4、加强纵深防御和最小特权原则:代码中使用存储过程,在代码被破坏时隐藏错误提示信息和应用程序逻辑;
5、总是关闭数据库的连接,防止“拒绝服务Dos攻击”。