SQL 注入攻击






4.30/5 (41投票s)
一篇关于SQL注入攻击的文章。
目录
- 引言
- SQL注入是如何工作的
- 如何找出正在工作的SQL服务器
- SQL注入的几个例子
- 防止SQL注入
- 参数化查询
- 存储过程
- 用于丢弃字符串的正则表达式
- Quoteblock函数
引言
曾经有一个时代,孩子们在看连环画长大的,但现在连环画有了动作,并演变成了动画卡通片。
网站最初只是向用户显示一些静态信息,使用纯HTML页面,并带有一些图形和彩色文本。很快,CGI等技术的出现使得在其上附加动态功能成为可能。网站能够查询在线数据库并满足请求。随着IT行业的飞速发展,网站很快就拥有了名为在线交易的强大武器。现在,网站不仅显示动态数据,还能接受客户订单并在网上处理。
数据库访问的整个过程的核心是数据库访问API。最终用户(访客)的输入由后端SQL引擎处理,以在数据库上执行CRUD操作(CRUD - 创建、读取、更新、删除)。
SQL注入是如何工作的
SQL注入不再是“所有输入都是恶意的”这一黄金法则的例外。SQL注入就是以一种不再满足预期结果的方式,对数据库执行CRUD操作,而是让攻击者有机会使用您网站的前端在数据库上运行自己的SQL命令。
好吧,大部分文本框输入是攻击者最好的朋友。但是,任何顺利进入数据库的输入都不安全。
让我们举个例子。像下面这样的正常查询
Select * from customers
对于SQL注入是安全的。正如我们所见,其中没有用户输入。像下面这样的交互式查询
select * from customers where customerID = 'ALFKI'
如果ALFKI是用户输入,那就是SQL注入的警报。用户输入指的是通过应用程序前端获得的数据。让我们假设有一个文本框(也可以是组合框),最终用户可以在其中输入客户姓名,然后您的应用程序将执行查询数据库的查询结果。
如果是组合框,攻击者可以先将您的页面以HTML格式保存,然后制作组合框的值字段以进行攻击。然而,他所能做的最好的事情就是对您的页面进行离线分析,然后制作一个应用程序,该应用程序将使用与输入控件相同的名称直接向您的应用程序发送GET或POST请求,从而绕过您的前端脚本验证。制作这种应用程序非常容易。一个有1年Web应用程序开发经验的普通程序员就可以做到。
所以,让我们看一个恶意用户输入的例子。如果用户在文本框中输入以下字符串而不是客户姓名。那么后台运行的SQL Server将锁定服务器。这实际上取决于服务器的配置错误程度。
a' exec master.dbo.xp_cmdshell 'rundll32.exe user32.dll,LockWorkStation'
所以,如果你想让一个网站无法访问,而服务器配置错误,那么你可以运行'iisreset/Stop'命令。这是完整的输入
a' exec master.dbo.xp_cmdshell 'iisreset/Stop'
然而,这仅仅是提示。实际上,攻击者更愿意获取服务器中存储的信息,以访问其中存储的有价值数据。而真实的数据就是金钱。想想看,如果有一个糟糕设计的应用程序,攻击者能够获取关于客户信用卡号或个人电子邮件地址以及他们个人信息(如家庭住址)的信息,他可能会在那里犯下身体犯罪,或者将电子邮件卖给垃圾邮件发送者。
咚咚咚……“女士,我是abc.com的,这是您在网站上下的订单”,在某个日期……从而获得了您客户家的实际访问权限。
如何找出正在工作的SQL服务器
然而,在打破网站进行访问之前,攻击者需要知道后端是什么SQL引擎,而从一个设计糟糕的系统获取这一点简直是小菜一碟。甚至在尝试之前,还有另一种方法叫做猜测。
如果您的网站有像.asp、.aspx等网页扩展名,那么很有可能是SQL Server或MS Access。如果页面以.jsp结尾,那么可能是Oracle系统。如果页面以.php结尾,我猜是MySQL。然而,如果我的猜测是错误的,我可以随时开始做实际工作。让我们看看如何找出后端是什么SQL引擎。要识别后端SQL服务器,所需的最低资格是SQL的初级经验。用于找出后端SQL引擎的通用工具是字符串连接字符和注释字符。
- 对于SQL Server:ALFKI和AL + FKI是相同的。
- 然而,对于Oracle,ALFKI和ALF || KI是相同的。
所以,输入AL+FKI,如果你得到一个错误,那就意味着后端绝对不是SQL Server。现在你可以继续尝试其他数据库的字符串连接语法,直到找到你得到正确结果为止。
攻击者通常像特种兵一样工作,而不是像一个手里拿着枪的未成年人。他们总是把正确的工具放在手边。我的意思是,攻击者会准备好文本文件,里面有现成的查询,攻击只是一个快速复制粘贴的问题。
使用SQL引擎定义的函数也是缩小范围的好例子,例如,您可以使用日期函数来找出后端是什么服务器:Oracle的Sysdate
,SQL Server的Getdate
。
使用用于结束SQL语句的字符也是找出后端SQL引擎的一个好方法。
我们无法阻止这类攻击,因为即使向攻击者显示错误页面,也等于让他知道输入的字符串是错误的。然而,黄金法则是在错误页面中不要向用户显示完整的详细错误消息,而是只说发生了一些错误,这样您就可以免受攻击者将要造成的进一步损害。因为,SQL注入攻击通常利用返回的错误消息来深入攻击过程。
SQL注入的几个例子
让我们看看一些流行的攻击类型
常见的攻击有
- 找出数据库中的表。
- 找出数据库中的列名。
- 使用
ORDER BY
子句找出数据库中使用的列数。
作为微软的爱好者,我将使用MS SQL Sever。这并不意味着它很弱。但我感觉使用MS SQL Server很自在。首先,让我们看一个简单的查询,找出数据库中有哪些表:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
此查询返回数据库中的用户定义表,攻击者可以使用此查询找出系统中存在的表。要找出表中存在的列,紧随其后的下一个查询是
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='customers'
您可能会想,攻击者将如何直接在您的系统中执行这些查询。答案是,他可以很容易地找出返回结果集中的列数,然后与返回的结果进行Union
。
像这样的简单命令
UNION select table_name , null ,null ,null
在这种情况下很有帮助。让我们再看一遍旧的查询
select * from customers where customerID = 'ALFKI'
易受攻击的查询将是
select * from customers where customerID = 'ALFKI'
union
SELECT table_name,null,null,null,null,null,null,null,null,
null,null FROM INFORMATION_SCHEMA.TABLES --'
利用字符串(从下面的单引号开始)
' union
SELECT table_name,null,null,null,null,null,null,null,
null,null,null FROM INFORMATION_SCHEMA.TABLES --
然而,现在您会惊讶于攻击者如何找出要附加的null
的数量。所以答案很简单:通过查看正常查询在HTML页面上产生结果时的输出来查看,或者使用ORDER BY
子句。
select * from customers where customerID = 'ALFKI' Order by 1 -- ‘
select * from customers where customerID = 'ALFKI' Order by 15 -- ‘
将导致攻击者出错。然而
select * from customers where customerID = 'ALFKI' Order by 11 -- ‘
不会出错,所以攻击者现在知道返回结果中只有11列。
我在这里停止讨论,其余的就靠您的想象了。
一些更高级的SQL注入形式(仅限MS SQL)
通过SQL注入技术,可以进行更高级的攻击。这可以通过注入包含调用sp_addlinkedserverlogin
的SQL字符串来完成。然而,这也取决于SQL注入运行的帐户的权限。类似地,openrowset
、Openquery
函数可以为攻击者提供机会,使用暴力破解技术猜测您的密码。更多详情,请参阅此。
防止SQL注入
用于防止SQL注入的各种技术是
- 参数化查询
- 存储过程
- 用于丢弃输入字符串的正则表达式
Quoteblock
函数- 不要向用户显示详细的错误消息。
- 让您的应用程序在数据库中使用权限较低的用户/角色。
SQL注入是可以防止的。然而,关于它们存在一些误解(例如,如果我使用存储过程就很安全)。一条规则仍然适用:“不要向用户显示详细的错误消息”。防止SQL注入的基本方法是让字符串输入作为字符串输入到SQL Server。这可以通过在将输入提供给服务器之前检查字符串终止符字符来完成。使用参数化查询和存储过程等技术可以免费为您做到这一点。但我仍然建议您在其中使用Quoteblock
函数(MS SQL Server)。其他预防措施将仅限于仔细决定授予您用于使SQL服务器和Web服务器之间通信成为可能的服务帐户的执行命令的权限。一个方便的技巧是不要在应用程序中使用动态SQL。动态SQL就像(MS SQL)。
Sp_executesql(‘string from the user’)
或者
exec (‘string from the user’)
我想在这里补充一点:不要只依赖正则表达式和其他字符串处理函数来丢弃输入,因为SQL注入可能以编码形式而不是简单的可读语言出现。
另一种方法是让一个Snort规则为您工作。然而,关于Snort规则及其实现的讨论超出了本文的范围。Snort规则可以帮助您检测网络中发生的SQL注入入侵。Snort通常会向您发送警报或记录入侵尝试。有关Snort规则的更多详细信息,请参阅此页面。
在下一部分,我将介绍脚本注入的详细信息,攻击者如何使用它以及如何防止它们。