随笔都是学习笔记
随笔仅供参考,为避免笔记中可能出现的错误误导他人,请勿转载。
posts - 398,comments - 0,views - 13万

简介:

参数化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   时间完全不够用啊  阅读(211)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示