前一篇文章,主要介绍了如何正确显示用户输入的包含特殊符号的信息,避免打乱页面结构,防止脚本攻击。上述可能出现的问题仅仅当这些输入信息没有与数据库打交道,如果这些信息作为数据库查询使用,那会造成什么后果呢?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>
数据表中的所有数据记录如下:

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

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

造成这种问题的原因在于,直接使用未处理的包含特殊符号的输入信息拼接生成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 ',提交查询,结果显示页面没有任何记录显示,这表明输入的特殊符号被正确转义。这个结论可以被再次证明,在数据库中增加一条记录,如下:

再次查询,结果页面显示如下图:

由此,可以证明输入的特殊符号确实被转义了,避免了SQl注入问题。
三、总结
编写sql不要采用拼接方式给变量赋值,一定要采用占位符预生成方式。该方式不仅可以有效避免SQL注入问题,还可以提高sql执行效率,无需多次编译。