Sql-Server应用程序的高级Sql注入(9)
即使这样攻击依然可能实现:如果攻击者可以不经过程序而往系统插入数据。比如攻击者有一个email接口,或者有一个可以控制的错误记录数据库。最好总是验证所有的数据,包括系统里的数据,验证函数调用很简单,比如:
if ( not isValied( "email", request.querystring("emil") ) ) then
response.end
或者其他的方法
[长度限制]
有时候输入对数据的长度加以限制会使攻击困难许多,这的确阻止了一些攻击,但一个很短的SQL语句也可能造成非常大的危害:
Username: ';shutdown--
关闭SQL-Server,只用了12个字符。另一个例子:
drop table <tablename>
如果长度限制是在字符串过滤后,另一个问题可能会发生。假设用户名被限制在16个字符之内,密码也被限制在16个字符之内,下面的用户名和密码结合可以执行'shutdown'命令:
Username:aaaaaaaaaaaaaaa'
Password:'; shutdown--
原因是程序过滤用户名最后的单引号,但是字符串又被切回到16个字符,删除了过滤的单引号。结果是密码域可以包含一些SQL, 只要它以一个单引号开始,最后的查询会变成这样:
select * from users where username = 'aaaaaaaaaaaaaa'' and password=''';shutdown--
用户名在查询里就变成:
aaaaaaaaaaaaaaa' and password='
后面附上的SQL被执行。
[躲避审核]
SQL Server在sp_traceXXX系列的函数包含丰富审核接口,它可以记录任何数据库里的事件。这里我们特别感兴趣的是T-SQL事件,它记录了所有的SQL语句以及服务器上准备好的和已运行了的批处理。如果这个级别的审核开启的话,所有我们讨论的注入都将被记录下来有经验的数据库管理员将会看到所有发生的事情。但是如果攻击者附加下面的字符:
sp_password
到一个Transact-SQL语句,这个审核记录如下:
-- 'sp_password' was found in the text of this event.
-- The text has been replaced with this comment for security reasons.
这在所有的的T-SQL日志记录时都会发生,即使'sp_password'出现在注释中。这当然是在用户传递sp_password时有意隐藏用户的明文密码,但这对攻击者相当有用。
所以,为了隐藏所有的注入攻击者只需要在注释符'--'后面加一个字符串:
Username: admin'--sp_password
事实上一些执行了的SQL将被记录,但是查询字符串本身被强制不记录。
[防 范]
这部分讨论一些针对这些攻击的防范措施。输入验证已经讨论过了,一些代码也给出了,后面我们研究SQL-Server防范问题。