学习目标:
在这里收集总结一下常见漏洞的修复方案吧,给自己三天时间收集整理,尽量详细。 下面都是从
- 是什么
- 为什么
- 怎么做
来回答
SQL注入漏洞
预编译
- 什么是预编译
数据库接收到sql语句之后,需要词法和语义解析,优化sql语句,制定执行计划。这需要花费一些时间。但是很多情况,我们的一条sql语句可能会反复执行。在某种情况下,多条SQL语句都只有某些关键字不同。所以为了优化SQL语句的执行效率,所有产生了SQL预编译,当然这也成为了防止SQL注入的最好方式。预编译就是将这类语句的值用占位符代替:如下面的问号。
//赋值语句用?代替
string sql = "select id from users where username = ? and password= ?";
ps = connection.preparestatement(sql);
//在给?赋值之前,预编译就会把上面的语句送入数据库进行解析,如果没有
//错的话就会返回
//给?赋值
ps.setstring(1,tom);
ps.setstring(2,passwd);
resultset=psmt.executeQuery();
预编译语句被DB的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中(相当于一个涵数)就会得到执行。 预编译是用过PreparedStatement和占位符来实现的。
-
为什么会防止SQL注入 使用预编译,而其后注入的参数将不会再进行SQL编译。也就是说其后注入进来的参数系统将不会认为它会是一条SQL语句,而默认其是一个参数,参数中的or或者and 等就不是SQL语法保留字了。 这最主要是由于不带占位符的拼接必须要用单引号’来包裹SQL字符串,而占位符的填写无需单引号,即使填入的变量是String str = “‘admin’”,那么JDBC也会将其中的单引号’ '转化成纯字符单引号处理,而不会被当做SQL的特殊字符单引号’来处理 总结: SQL语句的执行过程:提交SQL语句 -> 数据库引擎对SQL语句进行编译得到数据库可执行的代码 -> 执行SQL代码 SQL注入漏洞发生在数据库引擎对SQL语句编译的过程,而使用了preparestatement后 SQL语句在插入参数之前就已经完成了编译过程,在插入参数后会直接执行而不经过编译过程 -
怎么预防SQL注入 不使用普通的statement直接执行,使用preparestatement预编译
贴一段代码,看过上面的解释后这个代码也能很轻松的理解
//使用了preparestatement预编译的样子
<pre>
public void fix(HttpServletRequest request, Connection c, org.apache.log4j.Logger logger) {
String text = request.getParameter("text");
String sql = "select * from tableName where columnName = ?";
try {
PreparedStatement s = c.prepareStatement(sql);
s.setString(1, text);
s.executeQuery();
} catch (SQLException e) {
logger.warn("Exception", e);
}
}
</pre>
|