随笔都是学习笔记
随笔仅供参考,为避免笔记中可能出现的错误误导他人,请勿转载。

简介:

参数化SQL语句发送接口;

在sql语句中使用 ' ? ' 占位符表示参数;

只会进行

一个对象绑定一条SQL语句。

所在包:

Module java.sql
Package java.sql
Interface PreparedStatement

继承关系:

public interface PreparedStatement
extends Statement

创建方法:

使用的是Connection接口中的方法:

PreparedStatement prepareStatement​(String sql) throws SQLException
  sql:绑定的模板,一个SQL语句可能包含一个或多个'?'在参数占位符

设置参数的方法:

public void setString​(int parameterIndex, String x) throws SQLException
这是一个设置String类型参数的方法:
  parameterIndex: 第几个参数
  x:参数的值

setString()是设置String类型的参数,那么可以想到setDouble()就是设置double类型的参数,一次类推,数据库中需要什么类型的参数就使用对应的方法。

执行方法:

PreparedStatement执行SQL的方法没有参数,因为它在创建的时候就和SQL语句绑定在一起的了,换句话说就是只能执行创建时绑定的那条SQL语句。

和Statement对象一样:

public ResultSet executeQuery() throws SQLException

执行这个方法返回ResultSet对象;

public int executeUpdate() throws SQLException

执行这个方法返回影响的行数。

 

SQL攻击:

SQL攻击就是利用程序传递参数时的识别语句漏洞进行跨权限访问。

做一个简单的案例:

在MySQL数据库中创建一个表:

create table t_user (
    username VARCHAR(50),
    `password` VARCHAR(50)
);

INSERT INTO t_user VALUE('zs','123');
INSERT INTO t_user VALUE('ls','123');
INSERT INTO t_user VALUE('ww','123');

创建一个方法连接数据库:

public boolean login2(String tusername,String tpassword) throws Exception {
        Connection con = null;
        Statement st = null;
        ResultSet rs = null;
        try {
            // 四个参数
            String driverClassName = "com.mysql.jdbc.Driver";
            String url = "jdbc:mysql://localhost:3306/db1";
            String username = "root";
            String password = "747699";
            
            //加载驱动
            Class.forName(driverClassName);
            
            // SQL模板
            String sql = "select * from t_user where username='"+tusername+"' and password='"+tpassword+"'";

            // 注册驱动
            con = DriverManager.getConnection(url, username, password);

            // 获取SQL对象
            st = con.createStatement();

            // 发送SQL获得ResultSet对象
            rs = st.executeQuery(sql);

            return rs.next();    // 存在着返回true
        } finally {    // 关闭资源
            if (rs != null)
                rs.close();
            if (st != null)
                st.close();
            if (con != null)
                con.close();
        }
    }

然后创建测试方法:

    @Test
    public void fun1() throws Exception {
        boolean isOk = login2("zs", "123");
        System.out.println(isOk);
    }

结果:

返回true就说明输入的参数在数据库中;

那么如果把传入的参数换一种方式:

  @Test
    public void fun1() throws Exception {
        boolean isOk1 = login2("zs", "123");
        boolean isOk2 = login2("ls", "123");
        boolean isOk3 = login2("a' or 'a'='a", "a' or 'a'='a");
        System.out.println(isOk1);
        System.out.println(isOk2);
        System.out.println(isOk3);
    }

再查看输出结果:

可以发现还是返回的true,再看SQL语句就能明显的找出问题了,因为在SQL语句识别判断的时候,使用的是 or  'a'='a' 永真的语句,那么根本不用知道用户名和密码就能直接进入访问。

所以为了杜绝这种问题,就需要使用PreparedStatement接口将SQL语句参数化。

 

SQL语句参数化:

同样先创建方法连接数据库:

public boolean login1(String tusername, String tpassword) throws Exception {
        Connection con = null;
        PreparedStatement st = null;
        ResultSet rs = null;
        try {
            // 四个参数
            String driverClassName = "com.mysql.jdbc.Driver";
            String url = "jdbc:mysql://localhost:3306/db1";
            String username = "root";
            String password = "747699";
            
            //加载驱动
            Class.forName(driverClassName);
            
            // SQL模板
            String sql = "select * from t_user where username=? and password=?";

            // 注册驱动
            con = DriverManager.getConnection(url, username, password);

            // 获取SQL对象
            st = con.prepareStatement(sql);

            // 设置参数
            st.setString(1, tusername);    // 设置第一个问号
            st.setString(2, tpassword);    // 设置第二个问号

            // 发送SQL获得ResultSet对象
            rs = st.executeQuery();

            return rs.next();    // 存在着返回true
        } finally {    // 关闭资源
            if (rs != null)
                rs.close();
            if (st != null)
                st.close();
            if (con != null)
                con.close();
        }
    }

这里是使用的PreparedStatement对象,然后创建测试方法:

  @Test
    public void fun1() throws Exception {
        boolean isOk1 = login1("zs", "123");
        boolean isOk2 = login1("ls", "123");
        boolean isOk3 = login1("'a' or 'a'='a'", "'a' or 'a'='a'");
        System.out.println(isOk1);
        System.out.println(isOk2);
        System.out.println(isOk3);
    }

查看结果:

这下就不能通过判断了。

 

posted on 2022-05-04 11:14  时间完全不够用啊  阅读(142)  评论(0编辑  收藏  举报