就是利用Statement类不能对数据库的特殊符号做解释而被一些别有用心之人攻击。
SQL注入攻击会使得我们数据库的信息极为不安全。
案例:SQL注入攻击的代码案例
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
dataInfo();
}
public static void dataInfo() {
Scanner sc = new Scanner(System.in);
System.out.print("请输入用户名:");
String user_Name = sc.nextLine();
System.out.print("请输入密码:");
String user_password = sc.nextLine();
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
String url = "jdbc:mysql://127.0.0.1:3306/cgb2111?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
String userName = "账号";
String password = "密码";
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection(url, userName, password);
stat = conn.createStatement();
String sql = "select `id`, `name`, `pwd` from `user` where `name` = '" + user_Name + "' and `pwd` = '" + user_password + "'";
rs = stat.executeQuery(sql);
if (rs.next()) {
System.out.println("恭喜您,登录成功");
} else {
System.out.println("用户名或者密码错误");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
try {
if (rs != null && rs.isClosed() == false){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (stat != null && rs.isClosed() == false){
stat.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null && conn.isClosed() == false){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
【运行结果】
请输入用户名:赵敏' #
请输入密码:
恭喜您,登录成功
问题:当用户输入特殊值:jack' #时,甚至不需要密码也能登录
原因:# 在SQL中表示注释的意思,相当于后面的条件被注释掉了...
select `id`,`name`, `pwd` from user where name = '赵敏' #' pwd = '';
现象叫SQL注入/SQL攻击,本质上就是因为SQL语句中出现了特殊的符号。
导致了SQL语义发生了改变。
Statement低效、不安全。
解决方案:放弃Statement的使用,改用PreparedStatement。
解决SQL注入攻击的,改造后的代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
dataInfo();
}
public static void dataInfo() {
Scanner sc = new Scanner(System.in);
System.out.print("请输入用户名:");
String user_Name = sc.nextLine();
System.out.print("请输入密码:");
String user_password = sc.nextLine();
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
String url = "jdbc:mysql://127.0.0.1:3306/cgb2111?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
String userName = "账号";
String password = "密码";
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection(url, userName, password);
String sql = "select `id`, `name`, `pwd` from `user` where `name` = ? and `pwd` = ? ";
conn = JarDriver.getConnection();
ppst = conn.prepareStatement(sql);
ppst.setString(1, userName);
ppst.setString(2, userPassword);
rs = ppst.executeQuery();
if (rs.next()) {
System.out.println("恭喜您,登录成功");
} else {
System.out.println("用户名或者密码错误");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
try {
if (rs != null && rs.isClosed() == false){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (stat != null && rs.isClosed() == false){
stat.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null && conn.isClosed() == false){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
【运行结果】:
请输入用户名:赵敏' #
请输入密码:
用户名或者密码错误
封装数据库连接代码和释放资源代码
对于多次使用的JDBC与数据库连接的代码和释放资源的方法,我们可以采用封装的方法。这样只要编写一次,以后要使用时,直接调用封装的方法即可。这样可以节省我们大量的开发时间和提高开发效率。
封装代码的步骤:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JarDriver {
public static Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://127.0.0.1:3306/cgb2111?characterEndcoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&allowPublicKeyRetrieval=true";
String userName = "账号";
String password = "密码";
Connection conn = DriverManager.getConnection(url, userName, password);
return conn;
}
public static void close(Connection conn, PreparedStatement preps, ResultSet rs) {
try {
if (rs != null && rs.isClosed() == false){
rs.close();
System.out.println("ResultSet连接已经关闭");
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (preps != null && preps.isClosed() == false){
preps.close();
System.out.println("PreparedStatement连接已经关闭");
}
} catch (SQLException e){
e.printStackTrace();
}
try {
if (conn != null && conn.isClosed() == false) {
conn.close();
System.out.println("Connection连接已经关闭");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close(Connection conn, PreparedStatement preps) {
try {
if (preps != null && preps.isClosed() == false){
preps.close();
System.out.println("PreparedStatement连接已经关闭");
}
} catch (SQLException e){
e.printStackTrace();
}
try {
if (conn != null && conn.isClosed() == false) {
conn.close();
System.out.println("Connection连接已经关闭");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}



