11-java安全基础——java中的sql注入

Posted songly_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了11-java安全基础——java中的sql注入相关的知识,希望对你有一定的参考价值。

jdbc中的sql注入

JDBC是sun公司制定的使用java语言来操作数据库的驱动接口,程序员如果要开发访问数据库的程序,只需要会调用 JDBC 接口中的方法即可,不用关注类是如何实现的。

新建一个maven项目,导入jdbc依赖包:

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>
    </dependencies>

JDBC提供的开发接口:

java.sql :所有与 JDBC 访问数据库相关的接口和类

javax.sql :数据库扩展包,提供数据库额外的功能。如:连接池

DriverManager 类 :管理和注册数据库驱动 ,数据库连接对象

Connection 接口 :一个连接对象,可用于创建 Statement 和 PreparedStatement 对象

Statement 接口 :一个 SQL 语句对象,用于将 SQL 语句发送给数据库服务器

PreparedStatemen 接口 :一个 SQL 语句对象,是 Statement 的子接口

ResultSet 接口 :用于封装数据库查询的结果集,返回给客户端 Java 程序

来看一个简单的JDBC示例程序,查询一个用户:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;

/**
 * @auther songly_
 * @data 2021/8/12 19:30
 */
public class JdbcTest {
    public static void main(String[] args) throws Exception {
        //1.注册驱动
        Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
        //2.获取数据库连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis_test", "root", "123456");
        Scanner scanner = new Scanner(System.in);
        System.out.print("输入要查询的id:");
        String id = scanner.nextLine();
        //3.构造sql语句
        String sql = "select * from user where id = " + id;
        //4.获取执行sql的对象 Statement
        Statement statement = connection.createStatement();
        //5.执行sql
        ResultSet resultSet = statement.executeQuery(sql);
        //6.输出结果
        String username;
        String password;
        while (resultSet.next()) {
            id = resultSet.getString("id");
            username = resultSet.getString("username");
            password = resultSet.getString("password");
            System.out.println(id + " , " + username + " , " + password);
        }
        //7.释放数据库资源
        statement.close();
        connection.close();
    }
}

当我们输入id为1 or 1=1时,程序会把所有的结果查询出来,从执行的sql语句来看,JDBC使用了拼接的方式构造sql语句,id的内容1 or 1=1破坏了原有的sql的语义,使得sql语句的作用发生了改变,产生了歧义性,因此产生了sql注入问题。

 jdbc提供了一个PreparedStatement对象来防止sql注入,PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它使用了预编译SQL语句的方式来防止sql注入。

对之前的程序进行改写,使用preparedStatement对象来执行sql

        Scanner scanner = new Scanner(System.in);
        System.out.print("输入要查询的id:");
        String id = scanner.nextLine();
        //3.构造sql语句,使用了占位符?
        String sql = "select * from user where id = ?";
        //4.获取执行sql的对象 preparedStatement
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setString(1 , id);
        ResultSet resultSet = preparedStatement.executeQuery();

程序执行结果:

 preparedStatement对象在构造sql语句时不是简单sql拼接的方式,而是使用了站位符?来构造SQL语句,prepareStatement方法首先会将sql语句发送给数据库进行预编译,然后调用了setString方法将id的值传给了preparedStatement对象。preparedStatement对象会将id的内容1 or 1=1被作为一个整体传给sql语句,没有破坏sql语句原有的语义,因此只能查询出id为1的用户。

通过查看源码发现,底层实际上对1 or 1=1这些内容使用了单引号进行了闭合,被当作要给整体赋值给id,由于id字段的数据类型是整形,只会取第一个字符1作为id的值,即id=1。

有小伙伴可能会说,既然底层使用了单引号进行了闭合,那我们也可以使用单引号再次闭合啊,我们输入1' or 1 = '1再次进行闭合:

实际上底层对单引号进行了转义,输入的内容仍然被当作一个整体赋值给id,因此使用preparedStatement对象来执行sql语句可以有效的防止sql注入。 

mybatis中的sql注入

mybatis是一个用于操作数据库的持久层框架,它内部对JDBC进行了封装,屏蔽了JDBC接口底层访问细节,开发人员只需通过mybatis框架提供的xml或者注解方式就可以完成数据库的持久化操作。

mybatis框架执行sql语句支持两种传参方式:${ }和# { },“#”符号会点语句进行预编译,而${ }只是进行string 替换,动态解析SQL的时候会进行变量替换,有可能会造成sql注入问题,因此在项目中尽量使用预编译方式#{ },当只能使用${ }方式的话,需要做好参数校验防止sql注入。

以上是关于11-java安全基础——java中的sql注入的主要内容,如果未能解决你的问题,请参考以下文章

11-java安全基础——java中的sql注入

网络安全基础——SQL注入漏洞

# 20155337《网络对抗》Exp9 Web安全基础

常见基础注入类型-SQL注入-web安全

20145301赵嘉鑫 《网络对抗》Exp9 Web安全基础实践

WEB安全基础之sql注入基础