什么是SQL注入
当我们使用Statement进行操作时,在执行sql语句时,存在参数拼凑成恒等表达式的问题,如以下代码
public class TestStatement {
public static void main(String[] args) {
String url = "jdbc:oracle:thin:@192.168.200.128:1521:XE";
String username = "HR";
String password = "123456";
Connection con = null;
Statement stm = null;
ResultSet rs = null;
Scanner scanner = new Scanner(System.in);
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
con = DriverManager.getConnection(url, username, password);
System.out.println("连接成功!");
// 3.查询所有年级数据
System.out.println("学生数据库系统登录界面");
System.out.print("请输入学号:");
int studentNo = Integer.parseInt(scanner.nextLine());
System.out.print("请输入密码:");
String pwd = scanner.nextLine();
// 3.1 准备sql语句
String sql = "select count(*) from student where studentno=" + studentNo +
" and loginpwd='" + pwd + "'";
// 3.2 创建statement对象
stm = con.createStatement();
// 3.3 执行sql语句
rs = stm.executeQuery(sql);
// 3.4 解析返回数据
int result = -1;
if (rs.next()) {
result = rs.getInt(1);
}
// 判断结果
if (result > 0) {
System.out.println("登录成功");
} else {
System.out.println("登录失败,学号或密码有误!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 4.释放资源
if (rs != null) {
rs.close();
}
if (stm != null) {
stm.close();
}
if (con != null) {
con.close();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("断开连接!");
}
}
}
当我们输入
' or 1=1 --'
时,无论如何都能登陆数据库(产生了恒等式,--'' 变为了注释)
select count(*) from student where studentno=1000 and loginpwd='' or 1=1
上述情况,我们把它成为SQL注入问题
PreparedStatement接口
-
继承自 Statement接口
-
执行的是预编译的 SQL 语句
-
比Statement对象使用起来更加灵活,更有效率
-
提高了代码的可读性和可维护性
-
提高了安全性
使用步骤如下:
1.声明PreparedStatement变量
2.使用带占位符的sql语句
3.创建PreparedStatement对象
4.设置每一个输入参数的值
5.执行sql语句
6.关闭PreparedStatement
优化代码如下:
public class TestPreparedStatement {
public static void main(String[] args) {
String url = "jdbc:oracle:thin:@192.168.200.128:1521:XE";
String username = "HR";
String password = "123456";
Connection con = null;
PreparedStatement stm = null;
ResultSet rs = null;
Scanner scanner = new Scanner(System.in);
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
con = DriverManager.getConnection(url, username, password);
System.out.println("连接成功!");
// 3.查询所有年级数据
System.out.println("学生数据库系统登录界面");
System.out.print("请输入学号:");
int studentNo = Integer.parseInt(scanner.nextLine());
System.out.print("请输入密码:");
String pwd = scanner.nextLine();
// 3.1 准备sql语句, sql语句中所有的值,都换成?进行占位
String sql = "select count(*) from student where studentno=? and loginpwd=?";
System.out.println(sql);
// 3.2 创建statement对象
stm = con.prepareStatement(sql);
// *****为sql中的占位符赋值****
stm.setInt(1, studentNo);
stm.setString(2,pwd);
// 3.3 执行sql语句
rs = stm.executeQuery();
// 3.4 解析返回数据
int result = -1;
if (rs.next()) {
result = rs.getInt(1);
}
// 判断结果
if (result > 0) {
System.out.println("登录成功");
} else {
System.out.println("登录失败,学号或密码有误!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 4.释放资源
if (rs != null) {
rs.close();
}
if (stm != null) {
stm.close();
}
if (con != null) {
con.close();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("断开连接!");
}
}
}
这样,我们就避免了SQL注入问题