前一篇文章,主要介绍了如何正确显示用户输入的包含特殊符号的信息,避免打乱页面结构,防止脚本攻击。上述可能出现的问题仅仅当这些输入信息没有与数据库打交道,如果这些信息作为数据库查询使用,那会造成什么后果呢?SQL注入!没错!有可能会造成SQL注入问题。本文主要讨论包含特殊符号的信息如何引发SQL注入以及如何防止该问题的发生。

一、环境搭建

  基于上篇文章使用的测试项目,配置好相关数据库,数据持久化使用Spring JdbcTemplate实现。在UserNameController增加查询函数queryByName,新建结果显示页面result.jsp,在index.jsp页面中增加查询表单,代码如下:

<!-- 在UserNameController类中加入以下代码 -->
@RequestMapping("/queryByName")
public String queryByName(Model model, @RequestParam String username) {
    String sql = "SELECT * FROM user WHERE username = '" + username + "'";
    List<User> list = jdbcTemplate.query(sql, new RowMapper<User>() {
        @Override
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            User user = new User();
            user.setId(rs.getInt(1));
            user.setUsername(rs.getString(2));
            user.setAge(rs.getInt(3));
            return user;
        }
    });

    model.addAttribute("users", list);
    return "result";
}

<!-- 新建result.jsp页面显示查询结果 -->
<ul>
    <c:forEach items="${users}" var="user">
        <li>${user.id}, ${user.username}, ${user.age}</li>
    </c:forEach>
</ul>

<!-- 在index.jsp中增加查询表单 -->
<form method="get" action="queryByName.do">
    <input type="text" name="username" value="">
    <input type="submit" value="提交">
</form>

  数据表中的所有数据记录如下:

QQ截图20151225131051.jpg

二、测试

  下面我们来查询用户名为:' or 1=1 or '的用户信息,在查询表单中输入' or 1=1 or ',如下图:

QQ截图20151225130726.jpg

  提交表单,页面显示了所有的数据结果(如下图),说明发生了SQL注入。想想,如果这样的事情发生在生产项目中,是多么重大的事故。
QQ截图20151225131304.jpg

  造成这种问题的原因在于,直接使用未处理的包含特殊符号的输入信息拼接生成sql语句,最终生成的sql语句如下:

SELECT * FROM user WHERE username = '' or 1=1 or ''

  上述生成的SQL语句相当于查询该表所有记录,该表的所有记录都将被查询用户获取。那如何避免这种问题呢?我们可以使用占位符预生成sql,替换直接使用参数值拼接生成sql。下面修改queryByName方法代码如下:

@RequestMapping("/queryByName")
public String queryByName(Model model, @RequestParam String username) {
    String sql = "SELECT * FROM user WHERE username = ?";
    List<User> list = jdbcTemplate.query(sql, new RowMapper<User>() {
        @Override
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            User user = new User();
            user.setId(rs.getInt(1));
            user.setUsername(rs.getString(2));
            user.setAge(rs.getInt(3));
            return user;
        }
    }, username);

    model.addAttribute("users", list);
    return "result";
}

  在查询表单重新输入' or 1=1 or ',提交查询,结果显示页面没有任何记录显示,这表明输入的特殊符号被正确转义。这个结论可以被再次证明,在数据库中增加一条记录,如下:

QQ截图20151225132634.jpg

  再次查询,结果页面显示如下图:
QQ截图20151225132853.jpg

  由此,可以证明输入的特殊符号确实被转义了,避免了SQl注入问题。

三、总结

  编写sql不要采用拼接方式给变量赋值,一定要采用占位符预生成方式。该方式不仅可以有效避免SQL注入问题,还可以提高sql执行效率,无需多次编译。

文章作者:admin
本文链接:https://javatech.wang/index.php/archives/57/
版本所有 ©转载时必须以链接形式注明作者和原始出处