web安全 SQL Injection

描述:

1.数据从一个不可信赖的数据源进入程序。在这种情况下,不能确定数据源的可信性。

2.数据用于动态地构造一个SQL查询。

 

以下代码动态地构造并执行了一个 SQL 查询,该查询可以搜索与指定名称相匹配的项。该查询仅会显示条目所有者与被授予权限的当前用户一致的条目。

 

String userName = ctx.getAuthenticatedUserName();
String itemName = request.getParameter("itemName");
String query = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ itemName + "'";
ResultSet rs = stmt.execute(query);


这一代码所执行的查询遵循如下方式:

 

 

 

SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;

 

 

 

但是,由于这个查询是动态构造的,由一个不变的基查询字符串和一个用户输入字符串连接而成,因此只有在 itemName 不包含单引号字符时,才会正确执行这一查询。如果一个用户名为 wiley 的攻击者为 itemName 输入字符串“name' OR 'a'='a”,那么构造的查询就会变成:

 

 

 

SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';

 

 

这种查询的简化会使攻击者绕过查询只返回经过验证的用户所拥有的条目的要求;而现在的查询则会直接返回所有储存在 items 表中的条目,不论它们的所有者是谁。

 

下面这个例子指出了不同的恶意数值传递给在上例中构造和执行的查询时所带来的各种影响。如果一个用户名为 wiley 的攻击者为 itemName 输入字符串“name'; DELETE FROM items; --”,那么构造成的查询语句将会变为两个:

 

 

 

 

SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'

 

 

 

众多数据库服务器,其中包括Microsoft(R) SQL Server 2000,都可以一次性执行多条用分号分隔的 SQL 指令。对于那些不允许运行用分号分隔的批量指令的数据库服务器,比如 Oracle 和其他数据库服务器,攻击者输入的这个字符串只会导致错误;但是在那些支持这种操作的数据库服务器上,攻击者可能会通过执行多条指令而在数据库上执行任意命令。

 

注意成对的连字符 (--);这在大多数数据库服务器上都表示下面的语句将作为注释使用,而不能加以执行 [4]。在这种情况下,注释字符的作用就是删除修改的查询指令中遗留的最后一个单引号。对于那些不允许按照这种方式使用注释的数据库,通常攻击者会按例 1 的方式进行攻击。如果攻击者输入字符串“name');DELETE FROM items; SELECT * FROM items WHERE 'a'='a”,则会创建以下三个有效指令:

 

 

 

SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';


解决方案

 

 

造成 SQL injection 攻击的根本原因在于攻击者可以改变 SQL 查询的上下文,使程序员原本要作为数据解析的数值,被篡改为命令了。当构造一个 SQL 查询时,程序员应当清楚,哪些输入的数据将会成为命令的一部分,而哪些仅仅是作为数据。参数化 SQL 指令可以防止直接窜改上下文,避免几乎所有的SQL injection 攻击。参数化 SQL 指令是用常规的 SQL 字符串构造的,但是当需要加入用户输入的数据时,它们就会创建捆绑参数,这些捆绑参数是一些占位符,用来存放随后插入的数据。捆绑参数可以使程序员清楚地分辨数据库中的数据,即其中有哪些输入可以看作命令的一部分,哪些输入可以看作数据。这样,当程序准备执行某个指令时,它可以详细地告知数据库,每一个捆绑参数所使用的运行时的值,而不会将数据解析成命令。

 

 

 

String userName = ctx.getAuthenticatedUserName();
String itemName = request.getParameter("itemName");
String query =
"SELECT * FROM items WHERE itemname=? AND owner=?";
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setString(1, itemName);
stmt.setString(2, userName);
ResultSet results = stmt.execute();

 

最后欢迎大家访问我的个人网站:1024s

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值