SQL注入
1 SQL注入的效果的演示
1.1 SQL注入代码
package cn.bdqn.demo03;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
public class Login {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//创建Scanner类对象,从控制台获取用户名和密码数据
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String user = sc.nextLine();//使用nextLine()方法获取字符串
System.out.println("请输入密码:");
String pwd = sc.nextLine();//使用nextLine()方法获取字符串
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获取连接对象
String url = "jdbc:mysql://127.0.0.1:3306/java221804";
String dbuser = "root";
String password = "123456";
Connection connection = DriverManager.getConnection(url, dbuser, password);
//3、获取发送SQL语句的对象
Statement statement =connection.createStatement();
//编写SQL语句
String sql = "SELECT * FROM user WHERE username='"+user+"' AND password = '"+pwd+"';";
//4、执行SQL语句
ResultSet resultSet=statement.executeQuery(sql);
if(resultSet.next()){
System.out.println("用户名和密码正确,登录成功");
}else{
System.out.println("用户名或密码不正确,登录失败");
}
//6、关闭资源
resultSet.close();
statement.close();
connection.close();
sc.close();
}
}
1.2 SQL注入效果
输入错误的用户名和密码,提示登录失败:
![](img/05输入的用户名或密码错误.png)
输入错误的用户名和密码,提示登录成功:产生了SQL注入
![06输入不存在的用户名和密码](img/06输入不存在的用户名和密码.png)
2 什么是SQL注入
在用户输入的数据中有SQL关键字或语法,并且关键字或语法参与了SQL语句的编译。导致SQL语句编译后的条件为true,一直得到正确的结果。这种现象就是SQL注入。
上面案例代码中,当你的用户名为 abc' or 1=1;# 密码为123,拼接到SQL语句中,变成如下效果:
SELECT * FROM user WHERE username='abc' or 1=1;#' AND password = '123';
此SQL语句or 后面1=1永远正确,#后面的成了注释,所以这条语句会将表中所有的数据查询出来,然后再做数据判断的时候,就会得到正确结果,从而说用户名和密码正确,登录成功
3 如何避免SQL注入
由于SQL注入产生的原因是在用户输入数据对SQL整合,整合后再发送到数据库进行编译产生的。所以为了避免SQL注入,就需要SQL语句在用户输入数据前就进行编译,成为完整的SQL语句,编译完成后再进行数据填充。这个操作需要使用PrepareStatement实现。
PrepareStatement解决SQL注入(重要)
PreparedStatement接口继承了Statement接口,执行SQL语句的方法与Statement执行SQL语句的方法相同。
1 PreparedStatement的应用
PreparedStatement的作用:
- 预编译SQL语句,效率高
- 安全,避免SQL注入
- 可以动态的填充数据,执行多个同结构的SQL语句
1.1 参数标记
//预编译SQL语句,SQL中的所有参数由?符号占位,这被称为参数标记。在执行SQL语句之前,必须为每个参数提供值。
String sql = "select * from user where userName = ? and password=?;";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
```
1.2 动态参数绑定
preparedStatement.sexXxx(下标,值):参数下标从1开始,为指定参数下标绑定值。Xxx表示数据类型。
//绑定参数,有多少个?绑定多少个参数值
preparedStatement.setString(1, userName);
preparedStatement.setString(2, pwd);
```
2 综合案例
package cn.bdqn.demo02;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
public class PreparedStatementDemo01 {
public static void main(String[] args) throws ClassNotFoundException,SQLException {
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String userName = sc.nextLine();
System.out.println("请输入密码:");
String pwd = sc.nextLine();
// 1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2、获得连接
String url = "jdbc:mysql://localhost:3306/java2217";
String user = "root";
String password = "123456";
Connection connection = DriverManager.getConnection(url, user, password);
// 3、获取发送SQL对象
String sql = "select * from user where userName = ? and password=?;";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 4、绑定参数,有多少个?绑定多少个参数值
preparedStatement.setString(1, userName);
preparedStatement.setString(2, pwd);
// 5、执行SQL语句,并处理结果
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
System.out.println("用户名和密码正确,登录成功");
} else {
System.out.println("用户名或密码错误,登录失败");
}
// 6、释放资源:与关闭流的方式一样,先开的后关,后开的先关
resultSet.close();
preparedStatement.close();
connection.close();
sc.close();
}
}