安全红线之SQL盲注总结

安全红线SQL盲注总结

安全级别: 高

安全风险: 可能会查看、修改或删除数据条目和表

 可能原因:

未对用户输入正确执行危险字符清理

技术描述:

Web 应用程序通常在后端使用数据库,以与企业数据仓库交互。查询数据库事实上的标准语言是 SQL(各大数据库供应商都有自己的不同版本)。Web 应用程序通常会获取用户输入(取自 HTTP 请求),将它并入SQL查询中,然后发送到后端数据库。接着应用程序便处理查询结果,有时会向用户显示结果。

如果应用程序对用户(攻击者)的输入处理不够小心,攻击者便可以利用这种操作方式。在此情况下,攻击者可以注入恶意的数据,当该数据并入 SQL 查询中时,就将查询的原始语法更改得面目全非。例如,如果应用程序使用用户的输入(如用户名和密码)来查询用户帐户的数据库表,以认证用户,而攻击者能够将恶意数据注入查询的用户名部分(和/或密码部分),查询便可能更改成完全不同的数据复制查询,可能是修改数据库的查询,或在数据库服务器上运行 Shell 命令的查询。

一般而言,攻击者会分步实现这个目标。他会先学习 SQL 查询的结构,然后使用该知识来阻挠查询(通过注入更改查询语法的数据),使执行的查询不同于预期。假设相关查询是:

SELECT COUNT(*) FROM accountsWHERE username='$user' AND password='$pass'

其中 $user 和 $pass 是用户输入(从调用构造查询的脚本的 HTTP 请求收集而来 - 可能是来自 GET 请求查询参数,也可能是来自 POST 请求主体参数)。此查询的一般用法,其值为 $user=john、$password=secret123。形成的查询如下:SELECT COUNT(*) FROM accountsWHERE username='john' AND password='secret123'

如果数据库中没有这个用户密码配对,预期的查询结果便是 0,如果此类配对存在(也就是数据库中有名称为“john”的用户,且其密码为“secret123”),结果便是 >0。这是应用程序的基本认证机制。但攻击者可以用下列方式来更改此查询。

攻击者可以提供单引号字符(')所组成的输入,使数据库发出错误消息,其中通常包含关于 SQL 查询的有价值的信息。攻击者只需在发送的请求中包含用户值 ',并在密码中包含任何值(如 foobar)。结果便是下列(格式错误)的 SQL 查询:SELECT COUNT(*) FROM accountsWHERE username=''' AND password='foobar'

这可能会产生以下错误消息(取决于后端所使用的特定数据库):查询表达式 'username = ''' AND password= 'foobar'' 中发生语法错误(遗漏运算符)。
这时攻击者便得知查询是根据表达式 username='$user' AND password='$pass' 来构建的。利用手边的 SQL 查询时需要这一关键信息。攻击者了解查询的格式后,下一步只需使用:

user = ' or 1=1 or ''=' password = foobar
生成的查询如下:
SELECT COUNT(*) FROM accounts WHERE username='' or 1=1or ''='' AND password='foobar'

这表示查询(在 SQL 数据库中)对于“accounts”表的每项记录都会返回 TRUE,因为 1=1 表达式永远为真。因此,查询会返回“accounts”中的记录数量,于是用户(攻击者)也会被视为有效。这个探测方法有若干变体,例如,发送 '; or \'(您应该记住,几乎所有供应商都有他们自己唯一的 SQL“版本”。具体地说,发送 ' having 1=1,也会生成错误消息,此消息会泄露有关列名称的信息。在某些情况下,用户输入不会并入字符串上下文(用单引号括住),而是并入数字上下文,换言之,就是依现状嵌入。因此,在这种情况下,可以使用输入字符串 1 having 1=1。

* 盲目 SQL 注入技术:

降低 SQL 注入攻击风险的一般方式,是禁止详细的 SQL 错误消息,攻击者通常便利用这些消息(如上述示例所说明),轻易找出容易遭受“SQL 注入”的脚本。
这个(以遮盖获取安全)解决方案可以利用称为“盲目 SQL 注入”的技术来略过,黑客不需要依赖返回 SQL 错误消息,便能找出容易遭受“SQL 注入”的脚本。

这项技术需要发送易受攻击的参数(被嵌入在 SQL 查询中的参数)已被修改的请求,将参数修改成,使响应指出是否在 SQL 查询上下文中使用数据。这项修改包括搭配原始字符串来使用 AND Boolean 表达式,使它一时得出 true,一时得出 false。在一种情况中,最终结果应该与原始结果相同(例如:登录成功),在另一情况中,结果应该不同(例如:登录失败)。在某些少见的情况中,得出 true 的 OR 表达式也很有用。

如果原始数据是数字,可以耍较简单的花招。原始数据(如 123)可以在一个请求中替换为 0+123,在另一个请求中替换为 456+123。第一个请求的结果应该与原始结果相同,第二个请求的结果应该不同(因为得出的数字是 579)。在某些情况中,我们仍需要上面所说明的攻击版本(使用 AND 和 OR),但并不转义字符串上下文。

盲目 SQL 注入背后的概念是,即使未直接收到数据库的数据(以错误消息或泄漏信息的形式),也可能抽取数据库中的数据,每次一个位,或以恶意方式修改查询。观念在于,应用程序行为(结果与原始结果相同,或结果与原始结果不同)可以提供关于所求值(已修改)之查询的单位元相关信息,也就是说,攻击者有可能规划出以应用程序行为(相同/不同于原始行为)的形式来影响其求值(单位元)的 SQL Boolean 表达式。

 

应用程序解决方案:

若干方法的补救方法是对用户的输入进行特殊字符的清理。对SQL盲注需要过滤上下文更改符号。如:单引号'、引号"、反斜杠转义单引号\'、反斜杠转义引号\"、结束括号)、分号;

应用程序采用动态拼接SQL语句方式导致SQL注入成为可能,所以在应用程序中,尽量避免SQL语句直接拼接,然后合理的javascript特殊字符校验配合服务器端过滤器过滤特殊字符方式,防止SQL注入攻击。一般采用方法如下:

1.   JDBC预编译SQL语句

采用JDBC的PreparedStatement,通过预编译并且存储在PreparedStatement对象池中。通过这种方法来设置输入参数,可防止攻击者通过注入错误字符(如单引号)来操纵SQL语句。

采用SQL拼接方式示例如下:

String sql = "select* from users where username = '" + username + "'";

try

{

Statementstat = conn. createStatement();

ResultSetrs = stat. executeQuery(sql);

}

采用预编译SQL语句示例如下:

String sql = "select* from users where username = ?";

try

{

PreparedStatementps = myConnection.prepareStatement(sql);

ps.setString(1,username);

ResultSetrs = ps.executeQuery();

}

2.  使用存储过程绑定变量

在存储过程中使用绑定变量不仅极大的提高了SQL查询速度,并有效的防止SQL盲注。

很多同学使用如下方式进行SQL查询,该方法因每次入参i_username不同,ORACLE数据库每次都会对该sql语句进行硬编码。

sql := 'select * from userswhere username = ''' || i_username ||''';

open o_cursor for sql;

 

使用绑定变量示例如下,该方法使用了绑定编码,即使每次i_username值不同,ORACLE也是一次硬解析,每次只需要软解析就可以了,极大的提高了查询数据,并有效防止SQL盲注。

sql := 'select *from users where username = :username';

open o_cursor for sql using i_useranme;

3.  使用commons Validator框架

使用struts集成框架commons validator完成数据校验需求。具体validation.xml配置规则请查询相关说明文档,本文再描述。

注:如果需要后台校验validation.xml配置规则,则action对应的from-bean需要继承ValidateForm(原因可查看源代码),否则在页面只是单纯的javascript校验,用户(攻击者)同样可以通过禁用javascript脚本非法输入。

4.  Javascript校验+自定义过滤器

这种方法与上面方法比较类似。该方法的基本思想是:在页面进行正常数据校验和特殊字符校验提示,然后再过滤器中进行特殊字符处理,如果发现用户非法输入特殊字符,则进行特殊字符处理,如统一跳转到特殊字符提示页面。在该方法中,javascript进行特殊字符校验是一个相同的操作,可以写一个公用js方法,在页面加载时,注册触发事件。

 

在项目当中,方法一和方法二是果断采用的方法,不允许出现类似错误实例代码。

chaofanga

2012-9-19

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值