JDBC-SQL注入攻击问题及解决方案

什么是SQL注入:

由于dao层中执行的SQL语句是拼接出来的,其中一部分内容是用户从用户端输入的,当传入数据包含SQL关键字时,就有可能通过这些关键字来改变SQL的语义,从而执行一些特殊的操作,这就称为SQL注入问题。

SQL注入攻击演示:

首先我们创建一张用户表,里面包含用户名和密码。

mysql> select * from user;
+----------+----------+
| username | password |
+----------+----------+
| 满满     |   123456 |
+----------+----------+
1 row in set (0.00 sec)
正常查询:
package com.JDBC;

import java.sql.*;

/**
 * @Created with IntelliJ IDEA
 * @Description:
 * @Package: com.JDBC
 * @author: FLy-Fly-Zhang
 * @Date: 2019/7/6
 * @Time: 18:03
 */
public class JDBCDemo1 {
    public static boolean login(String userName,String passwd){
        boolean result=false;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection connection =DriverManager.getConnection("jdbc:mysql://localhost:3306/sqldemo?SSL=false&serverTimezone=UTC","root","123456");
            String sql="select * from user where username="+userName+"and password="+passwd;
            Statement statement=connection.createStatement();
            ResultSet resultSet=statement.executeQuery(sql);
            if(resultSet.next())
                result=true;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (SQLException e) {
            e.printStackTrace();
        }
        return result;
    }
    public static void main(String[] args) {
         String name="'满满'"; //注意,数据库字符串需要+单引号
         String passwd="123456";
         boolean login=login(name,passwd);
         if(login){
             System.out.println("登陆成功");
         }else {
             System.out.println("登陆失败");
         }
    }

}
//结果,登陆成功
SQL注入攻击查询
package com.JDBC;

import java.sql.*;

/**
 * @Created with IntelliJ IDEA
 * @Description:
 * @Package: com.JDBC
 * @author: FLy-Fly-Zhang
 * @Date: 2019/7/6
 * @Time: 18:03
 */
public class JDBCDemo1 {
    public static boolean login(String userName,String passwd){
        boolean result=false;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection connection =DriverManager.getConnection("jdbc:mysql://localhost:3306/sqldemo?SSL=false&serverTimezone=UTC","root","123456");
            String sql="select * from user where username="+userName+"and password="+passwd;
            Statement statement=connection.createStatement();
            ResultSet resultSet=statement.executeQuery(sql);
            if(resultSet.next())
                result=true;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (SQLException e) {
            e.printStackTrace();
        }
        return result;
    }
    public static void main(String[] args) {
         String name="'满满'"; //注意,数据库字符串需要+单引号
         String passwd="1=1 or 12345";
         boolean login=login(name,passwd);
         if(login){
             System.out.println("登陆成功");
         }else {
             System.out.println("登陆失败");
         }
    }
}

//结果,登陆成功

如何解决SQL注入问题: 采用预编译的Statement对象处理

PreparedStatement 采用预编译机制将SQL语句的主干和参数分别传输数据库,数据库是可以分辨SQL语句的主干和参数,这样即使SQL中带有关键字,数据库也仅仅将其当参数使用,关键字就不会起作用。

prepareStatement优势:
  • 防止SQL注入
  • 使用预编译机制,执行效率是高于Statement
  • SQL语句中,参数值是通过?形式来替代参数,在使用preparedStatement方法直接进行拼接,相对于SQL直接拼接更加优雅。

Preparedstatement和statement的区别:

  1. 语法不同:Preparedstatement可以使用预编译的SQL,statement使用静态sql
  2. 效率不同:Preparedstatement因为使用预编译,因此在执行时,少了大量的解释代码时间
  3. 安全性:Preparedstatement能解决SQL注入问题。

解决方案代码演示:

package com.JDBC;

import java.sql.*;

/**
 * @Created with IntelliJ IDEA
 * @Description:
 * @Package: com.JDBC
 * @author: FLy-Fly-Zhang
 * @Date: 2019/7/6
 * @Time: 18:03
 */
public class JDBCDemo1 {
    public static boolean login(String userName,String passwd){
        boolean result=false;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection connection =DriverManager.getConnection("jdbc:mysql://localhost:3306/sqldemo?SSL=false&serverTimezone=UTC","root","123456");
            String sql="select * from user where username=? and password=?";
            PreparedStatement statement=connection.prepareStatement(sql);
            statement.setString(1,userName);
            statement.setString(2,passwd);
            ResultSet resultSet=statement.executeQuery();
            if(resultSet.next())
                result=true;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (SQLException e) {
            e.printStackTrace();
        }
        return result;
    }
    public static void main(String[] args) {
         String name="满满"; //注意,当使用PreparedStatement时,其会自动加单引号,不需要我们在加
         String passwd="1=1 or 123456";
         boolean login=login(name,passwd);
         if(login){
             System.out.println("登陆成功");
         }else {
             System.out.println("登陆失败");
         }
    }

}

//结果,登陆失败

猜你喜欢

转载自blog.csdn.net/Fly_Fly_Zhang/article/details/95018853