一、SQL注入概念
SQL注入是指一种代码注入技术,它通过Web页面请求或提交表单的形式,提交恶意的SQL,以此达到攻击数据库驱动的目的。
二、SQL注入原理
SQL注入可以使攻击者绕过认证机制,通过执行恶意的SQL,获取数据库数据或权限,进一步理由计算机漏洞达到获取计算机系统权限的目的。SQL是结构化查询语言的简称,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统。大多数应用服务器,其后台都会使用到数据库,因为SQL语法允许数据库命令和用户数据混杂在一起的,所以用户不仅可以通过Web输入数据,也可输入任意的SQL命令来操作数据库。
SQL注入式攻击的主要形式可以分为两种:
(1) 一种是直接注入攻击法。其将恶意SQL与原始SQL命令串联拼接在一起执行。如下面的例子:
原始SQL命令:
strSQL = "SELECT * FROM users WHERE name = '" + userName + "' and pw = '"+ passWord +"';
userName = "1' OR '1'='1";
passWord = "1' OR '1'='1";
注入后SQL:
SELECT * FROM users WHERE name = '1' OR '1'='1' and pw = '1' OR '1'='1
相当于执行了:
SELECT * FROM users WHERE name
(2) 一种是间接注入攻击法。其将原始的SQL当做是一个数据操作的指令,而将恶意SQL通过分号的形式与原始SQL分割开,当做两条命令来执行。一般在追加的前面会使用;来分割,后面使用--来注释尾部SQL,执行时就会仅执行原始SQL和恶意SQL。
不仅可以通过Web输入数据,也可输入任意的SQL命令来操作数据库。如下面例子:
同样是上面的语句,我们插入数据为:
userName = "'; DROP TABLE users--";
passWord = "'; DROP TABLE users--";
注入后SQL:
SELECT * FROM users WHERE name = ''; DROP TABLE users-- and pw = ''; DROP TABLE users--
相当于执行了:
SELECT * FROM users WHERE name = '';
DROP TABLE users;
至此就达到了删库跑路的目的。
三、SQL注入的一般过程
(1) 发现SQL注入位置
可以通过一些语句去试探动态页面的入参是否存在SQL注入的可能。
(2) 判断后台数据库类型
通过各个不同数据库独有的系统命令来判断。
(3) 确定XP_CMDSHELL可执行情况
需要系统本身存在SQL与系统命令之间的通道,以此通过数据库操作计算机。
(4) 发现WEB虚拟目录
(5) 上传ASP木马
(6) 得到管理员权限
四、防御SQL注入攻击
(1) 采用预编译语句集,将SQL原句编译后执行,这样参数不能改变原有原句的命令。Java实例如下:
采用JDBC的可以这样写:
String sql= "select * from users where username=? and password=?";
PreparedStatement preState = conn.prepareStatement(sql);
preState.setString(1, userName);
preState.setString(2, password);
ResultSet rs = preState.executeQuery();
对于IN查询,因为IN查询,因为预编译要确定参数的个数,所以可以采用如下写法:
PreparedStatement statement = connection.prepareStatement("Select * from test where field in (?)");
Array array = statement.getConnection().createArrayOf("VARCHAR", new Object[]{"A1", "B2","C3"});
statement.setArray(1, array);
ResultSet rs = statement.executeQuery();
或者判断入参的格式,构造IN(?,?,?)形式的入参。
采用Mybatis的可以这样写,XML文件:
<select id="getBlogById" resultType="Blog" parameterType=”int”>
SELECT id,title,author,content
FROM blog
WHERE id=#{id}
</select>
Java文件:
filter.put("title", id);
Blog blog = loanMerchantMemDao.getBlogById(filter);
采用Mybatis使用IN查询的可以这样写,XML文件:
<select id="findByTitle" resultMap="Blog" parameterType="java.util.Map">
SELECT
<include refid="Column"/>
FROM blog
WHERE title IN
<foreach collection="title" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
Java文件:
List<String> list = new ArrayList<String>();
filter.put("title", list);
Blog blog = loanMerchantMemDao.findByTitle(filter);
(2) 过滤敏感词汇和超出长度限制的输入,可以通过正则表达式或者方法判断提交的请求或参数中是否包含敏感词汇,例如; ' delete --等,然后过滤敏感词汇,或者禁止本次请求发生。
(3) 区分普通用户与系统管理员用户。服务器上应用访问数据库都应使用普通用户权限,防止其执行Drop Table,读取系统表结构、创建表等语句,这样在最大程度上可以减少注入攻击带来的危害。
参考: