上文jdbc不再是个谜中提到执行SQL语句的传输器类型Statement,其实该对象存在安全性问题,即“SQL注入问题”,防止SQL注入有很多方法,但是作为Statement类型的子对象——PreparedStatement类型的对象也是为了解决这个问题,这也是两个类型对象的区别,下面我们了解下。
Statement类型对象的使用
参考上篇jdbc不再是个谜
上述代码中存在一些问题:
用户名为:张三’ #
密码为:(空)
拼接后的SQL语句:
select * from user where username='张三'# ' and password=''
最终不用密码即可登录!
产生问题的原因是因为该SQL语句是字符串拼接而成的,这种方法传递的参数中如果带有“#、‘、–”等字符时,则会修改原来的SQL语句,从而达到非法获取数据的目的。
PreparedStatement类型的对象
package com.hopeful.jdbc;
import netscape.security.UserTarget;
import java.sql.*;
import java.util.Scanner;
public class LoginUser {
static Connection connection = null;
static PreparedStatement ps = null;
static ResultSet rs = null;
public static void main(String[] args) {
try {
// 获取连接
connection = Jutils.getConnection();
System.out.println("请登录");
System.out.println("请输入用户名");
Scanner scanner = new Scanner(System.in);
String user = scanner.nextLine();
System.out.println("请输入密码");
String password = scanner.nextLine();
loginUserByPreparStatement(user, password);
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
Jutils.releaseResource(rs, ps, connection);
}
}
private static void loginUserByPreparStatement(String user, String password) {
String sql = "select * from user where username = ? and password = ?";
try {
ps = connection.prepareStatement(sql);
ps.setString(1, user);
ps.setString(2, password);
ResultSet resultSet = ps.executeQuery();
if(resultSet.next()) {
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
用户名为:张三’ #
密码为:(空)
最终用户名和密码不正确无法登录!
该对象可以防止SQL注入的原因是,先把SQL语句模板发送到服务器,经编译后,SQL语句结构不会再发生变化,随后传递参数时,即使参数中包含SQL关键字或特殊字符(#、–、’)时,也只能作为普通文本进行处理,故不存在安全问题。
当然也可以使用正则表达式防止SQL攻击,当遇到SQL关键字或特殊字符时,提示非法输入而不进行参数传递,这里暂且提供思路。
该文如对你有用,请支持下哦!你的支持(收藏、点赞和关注)将是我写作的最大动力。