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

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

🍎个人主页:

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

💞当前专栏:

✨特色专栏:

🥭本文内容:【JAVA高级】——吃透JDBC定制设计中的问题和解决方案

定制设计更多内容点击👇

                       

本文目录


💖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. }

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

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发