小言_互联网的博客

【JAVA高级】——吃透JDBC中的SQL注入问题和解决方案

333人阅读  评论(0)

 ✅作者简介:热爱国学的Java后端开发者,修心和技术同步精进。

🍎个人主页:乐趣国学的博客

🍊个人信条:不迁怒,不贰过。小知识,大智慧。

💞当前专栏:JAVA开发者成长之路

✨特色专栏:国学周更-心性养成之路

🥭本文内容:【JAVA高级】——吃透JDBC中的SQL注入问题和解决方案

更多内容点击👇

                       【JAVA高级】——一文学会JDBC操作数据库

本文目录

💖SQL注入

✨什么是SQL注入

✨SQL注入的效果的演示

💫SQL注入代码

💫SQL注入效果

✨如何避免SQL注入

💖PrepareStatement解决SQL注入

✨PreparedStatement的应用

💫参数标记

💫动态参数绑定

✨综合案例

✨PreparedStatement总结

💖必须使用Statement的情况

💖投票传送门(欢迎伙伴们投票)


💖SQL注入

✨什么是SQL注入

        在用户输入的数据中有SQL关键字或语法,并且关键字或语法参与了SQL语句的编译。导致SQL语句编译后的条件为true,一直得到正确的结果。这种现象就是SQL注入

✨SQL注入的效果的演示

💫SQL注入代码


  
  1. package cn.bdqn.demo03;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.ResultSet;
  5. import java.sql.SQLException;
  6. import java.sql.Statement;
  7. import java.util.Scanner;
  8. public class Login {
  9. public static void main (String[] args) throws ClassNotFoundException, SQLException {
  10. //创建Scanner类对象,从控制台获取用户名和密码数据
  11. Scanner sc = new Scanner(System.in);
  12. System.out.println( "请输入用户名:");
  13. String user = sc.nextLine(); //使用nextLine()方法获取字符串
  14. System.out.println( "请输入密码:");
  15. String pwd = sc.nextLine(); //使用nextLine()方法获取字符串
  16. //1、注册驱动
  17. Class.forName( "com.mysql.jdbc.Driver");
  18. //2、获取连接对象
  19. String url = "jdbc:mysql://127.0.0.1:3306/java221804";
  20. String dbuser = "root";
  21. String pssword = "123456";
  22. Connection connection = DriverManager.getConnection(url, dbuser, pssword);
  23. //3、获取发送SQL语句的对象
  24. Statement statement =connection.createStatement();
  25. //编写SQL语句
  26. String sql = "SELECT * FROM user WHERE username='"+user+ "' AND pssword = '"+pwd+ "';";
  27. //4、执行SQL语句
  28. ResultSet resultSet=statement.executeQuery(sql);
  29. if(resultSet.next()){
  30. System.out.println( "用户名和密码正确,登录成功");
  31. } else{
  32. System.out.println( "用户名或密码不正确,登录失败");
  33. }
  34. //6、关闭资源
  35. resultSet.close();
  36. statement.close();
  37. connection.close();
  38. sc.close();
  39. }
  40. }

💫SQL注入效果

输入错误的用户名和密码,提示登录失败:

 输入错误的用户名和密码,提示登录成功:产生了SQL注入

        上面案例代码中,当你的用户名为 abc' or 1=1;# 密码为123,拼接到SQL语句中,变成如下效果:

        SELECT * FROM user WHERE username='abc' or 1=1;#' AND pssword = '123';

        此SQL语句or 后面1=1永远正确,#后面的成了注释,所以这条语句会将表中所有的数据查询出来,然后再做数据判断的时候,就会得到正确结果,从而说用户名和密码正确,登录成功。

✨如何避免SQL注入

        使用PreparedStatement代替Statement可以有效防止SQL注入的发生。由于SQL注入产生的原因是在用户输入数据对SQL整合,整合后再发送到数据库进行编译产生的。

        所以为了避免SQL注入,就需要SQL语句在用户输入数据前就进行编译,成为完整的SQL语句,编译完成后再进行数据填充。这个操作需要使用PrepareStatement实现。

        PreparedStatement利用预编译的机制将sql语句的主干和参数分别传输给数据库服务器,从而使数据库分辨的出哪些是sql语句的主干哪些是参数,这样一来即使参数中带了sql的关键字,数据库服务器也仅仅将他当作参数值使用,关键字不会起作用,从而从原理上防止了sql注入的问题。

💖PrepareStatement解决SQL注入

        PreparedStatement接口继承了Statement接口,执行SQL语句的方法与Statement执行SQL语句的方法相同。

✨PreparedStatement的应用

PreparedStatement的作用:

  • 预编译SQL语句,效率高

  • 安全,避免SQL注入

  • 可以动态的填充数据,执行多个同结构的SQL语句

💫参数标记

        //预编译SQL语句,SQL中的所有参数由?符号占位,这被称为参数标记。在执行SQL语句之前,必须为每个参数提供值。

        String sql = "select * from user where userName = ? and pssword=?;";

        PreparedStatement preparedStatement = connection.prepareStatement(sql);

💫动态参数绑定

        preparedStatement.sexXxx(下标,值):参数下标从1开始,为指定参数下标绑定值。Xxx表示数据类型。

        //绑定参数,有多少个?绑定多少个参数值

        preparedStatement.setString(1, userName);

        preparedStatement.setString(2, pwd);

✨综合案例


  
  1. package cn.bdqn.demo02;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.SQLException;
  7. import java.util.Scanner;
  8. public class PreparedStatementDemo01 {
  9. public static void main (String[] args) throws ClassNotFoundException,SQLException {
  10. Scanner sc = new Scanner(System.in);
  11. System.out.println( "请输入用户名:");
  12. String userName = sc.nextLine();
  13. System.out.println( "请输入密码:");
  14. String pwd = sc.nextLine();
  15. // 1、注册驱动
  16. Class.forName( "com.mysql.jdbc.Driver");
  17. // 2、获得连接
  18. String url = "jdbc:mysql://localhost:3306/java2217";
  19. String user = "root";
  20. String pssword = "123456";
  21. Connection connection = DriverManager.getConnection(url, user, pssword);
  22. // 3、获取发送SQL对象
  23. String sql = "select * from user where userName = ? and pssword=?;";
  24. PreparedStatement preparedStatement = connection.prepareStatement(sql);
  25. // 4、绑定参数,有多少个?绑定多少个参数值
  26. preparedStatement.setString( 1, userName);
  27. preparedStatement.setString( 2, pwd);
  28. // 5、执行SQL语句,并处理结果
  29. ResultSet resultSet = preparedStatement.executeQuery();
  30. if (resultSet.next()) {
  31. System.out.println( "用户名和密码正确,登录成功");
  32. } else {
  33. System.out.println( "用户名或密码错误,登录失败");
  34. }
  35. // 6、释放资源:与关闭流的方式一样,先开的后关,后开的先关
  36. resultSet.close();
  37. preparedStatement.close();
  38. connection.close();
  39. sc.close();
  40. }
  41. }

✨PreparedStatement总结

PreparedStatement主要有如下的三个优点:

        可以防止sql注入
        由于使用了预编译机制,执行的效率要高于Statement
        sql语句使用?形式替代参数,然后再用方法设置?的值,比起拼接字符串,代码更加优雅.

PreparedStatement 与Statment比较:

        语法不同:PreparedStatement可以使用预编译的sql,而Statment只能使用静态的sql
        效率不同: PreparedStatement可以使用sql缓存区,效率比Statment高
        安全性不同: PreparedStatement可以有效防止sql注入,而Statment不能防止sql注入。

💖必须使用Statement的情况

        当sql语句中必须用到字符串拼接时,则必须使用Statement


  
  1. public static void main (String[] args) {
  2. Scanner s = new Scanner(System.in);
  3. System.out.print( "升序输入asc,降序输入desc:");
  4. String order = s.nextLine();
  5. // 定义变量
  6. Connection connection = null;
  7. Statement statement = null;
  8. ResultSet rs = null;
  9. try {
  10. // 注册驱动
  11. Class.forName( "com.mysql.cj.jdbc.Driver");
  12. // 获取连接
  13. connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/MyTest", "root", "********");
  14. // 获取数据库操作对象
  15. statement = connection.createStatement();
  16. // 执行sql
  17. String sql = "select * from emp order by sal " + order;
  18. rs = statement.executeQuery(sql);
  19. // 处理查询结果集
  20. while(rs.next()){
  21. String ename = rs.getString( "ename");
  22. double sal = rs.getDouble( "sal");
  23. System.out.println( "姓名:" + ename + ",薪资:" + sal);
  24. }
  25. } catch (ClassNotFoundException | SQLException e) {
  26. e.printStackTrace();
  27. } finally {
  28. // 释放资源
  29. if (rs != null) {
  30. try {
  31. rs.close();
  32. } catch (SQLException e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. if (statement != null) {
  37. try {
  38. statement.close();
  39. } catch (SQLException e) {
  40. e.printStackTrace();
  41. }
  42. }
  43. if (connection != null) {
  44. try {
  45. connection.close();
  46. } catch (SQLException e) {
  47. e.printStackTrace();
  48. }
  49. }
  50. }
  51. }

💖投票传送门(欢迎伙伴们投票)

 


转载:https://blog.csdn.net/hh867308122/article/details/127539419
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场