Web开发安全之防止SQL注入

所谓SQL注入式攻击,就是输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存储过程的输入参数,这类表单特别容易受到SQL注入式攻击。

导致原因及可能后果

通过将带有恶意目的的SQL语句或参数写入表单中进行提交,程序未经过校验直接执行SQL语句,导致一些敏感数据泄露包括一些用户名密码信息等,以及可能会对数据库信息进行增删改操作,篡改数据等严重后果。

一些例子

直接动态拼接SQL语句

反例:

String username = request.getParameter("username");
String password = request.getParameter("password");
String encryptedPass = PasswordUtil.encrypt(password);
String sql = "select * from users where username = '" + username + "' and password = '" + encryptedPass + "'";
Statement s = c.createStatement();
ResultSet rs = s.executeQuery(sql);

正例:

String username = request.getParameter("username");
String password = request.getParameter("password");
String encryptedPass = PasswordUtil.encrypt(password);
String sql = "select * from users where "
            + "username = ? and password = ?";
PreparedStatement s = c.prepareStatement(sql);
s.setString(1, username);
s.setString(2, encryptedPass);
ResultSet rs = s.executeQuery();

如果用户登录时候在username和passwor分别填入

username = "‘1' or '1'='1‘";
password = "’1' or '1'='1’";

最终SQL语句就会变成

String sql = "select * from users where "
    + "username = '1' or '1'='1' and password = '1' or '1'='1'";

由于where条件永为真,那么最后相当于执行

String sql = "select * from users"

直接曝露所有用户信息。更有甚者,可将语句变为

String sql = "select * from users;drop table users;"

将用户数据全部删除。

因此,需要使用PreparedStatement对象而不是用Statement对象来预编译SQL语句。主要有三点优势:

  1. PreparedStatement可以写动态参数化的查询
  2. PreparedStatement比 Statement 更快
  3. PreparedStatement可以防止SQL注入式攻击

使用mybatis框架动态参数使用'$'而不是'#'

反例:

<dynamic prepend="where">
<isParameterPresent>
    <isNotEmpty prepend="and" property="onShelves">
        p.onshelves=$onShelves$
    </isNotEmpty>
</isParameterPresent>
</dynamic>

正例:

<dynamic prepend="where">
<isParameterPresent>
    <isNotEmpty prepend="and" property="onShelves">
        p.onshelves=#onShelves#
    </isNotEmpty>
</isParameterPresent>
</dynamic>

'#'解析为一个 JDBC 预编译语句(prepared statement)的参数标记符。而'$'仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换。
注意点:

  1. 能使用 #{}的地方就用 #{}
  2. 表名作为变量时,必须使用 ${}

如何防止

  1. 永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度;对单引号和双"-"进行转换等。
  2. 永远不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取。
  3. 可通过一些检查方法来进行安全测验。sql注入的检测方法一般采取辅助软件或网站平台来检测,软件一般采用sql注入检测工具jsky,网站平台就有亿思网站安全平台检测工具。

参考资料

  1. 利用SQL注入漏洞登录后台
  2. JDBC为什么要使用PreparedStatement
  3. mybatis之#和$区别

猜你喜欢

转载自www.cnblogs.com/universal/p/10477393.html