就是利用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(); } } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)