在上一章节中,我们使用 statement 执行 sql 完成了用户登录的小案例,但是在这个案例中也发现了 SQL 注入的问题。
而 SQL 注入的问题主要就是在字符串拼接中,存在查询条件拼接了 ' or '' = '
后,导致可以查询所有数据的情况。
那么为了解决这个问题,我们就需要固化查询语句的结构,不允许随意拼接字符串。那么下面我们来介绍使用 preparedStatement 解决 SQL 注入问题。
能够完成PreparedStatement改造登录案例, 解决SQL注入问题
预编译SQL语句对象, 是Statement对象的子接口。
特点:
connection.prepareStatement(String sql) ;创建prepareStatement对象
sql表示预编译的sql语句,如果sql语句有参数通过?来占位
SELECT * FROM user WHERE username = ? AND password = ?
那么下面我们使用 prepareStatement 来解决SQL注入,修改登录案例的代码如下:
public class LoginClient {
/**
* 使用 JDBC 实现登录案例
*/
public static void main(String[] args) throws SQLException {
//1. 获取用户输入的 用户名
System.out.println("请输入的用户名: ");
Scanner scanner = new Scanner(System.in);
String username = scanner.nextLine();
System.out.println("输入的用户名: " + username);
//2. 获取数据库连接
Connection connection = JdbcUtils.getConnection();
//3. 根据用户名执行数据查询
//String sql = "select * from t_user where uname = '" + username + "'"; // 设置SQL
//Statement statement = connection.createStatement(); // 获取statement
//ResultSet resultSet = statement.executeQuery(sql); // 执行查询SQL
// 使用 prepareStatement 来解决SQL注入
String sql = "select * from t_user where uname = ?"; // 设置SQL, 使用问号?设置查询的条件参数
PreparedStatement preparedStatement = connection.prepareStatement(sql); // 获取preparedStatement
// 设置SQL参数,执行SQL。
preparedStatement.setString(1, username); // 设置用户名参数
// 执行(还是executeQuery()和executeQUpdate(), 但是不需要再传入SQL语句, 上面已经传入了)
ResultSet resultSet = preparedStatement.executeQuery();
//4. 如果查询存在用户名的数据,那么则登录成功;反之,登录失败
if (resultSet.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
}
}
' or '' = '
字符串,执行SQL注入如下:可以看到,使用拼接字符串 ' or '' = '
已经不能再次查询成功了,也就解决了 SQL注入问题。