防止SQL攻击之PreparedStatement的使用

1. 导语

可能有点标题党 哈哈,现在一般的网站登录,用户名和密码被正则限制的死死的,一般很难有漏洞通过sql语句,登录进去,但是不妨碍我们做一个demo,看看怎么的漏洞能被sql利用,同时学习怎样加强防备使用PreparedStatement来预防。

2. 学习

一般我们登录时,一般会把我们的用户名和密码用来作为sql查询的条件,查询数据库,如果能查到则说明有次用户,如果查不到当然无此用户。查询时我们一般都是在java代码中操作的,所以就用到 JDBC
jdbc

2.1 建表插入数据


这里写图片描述

如上图,这里准备了一张 student 表,其中的 studentname 、stupsd 分别当作用户名和密码

2.2 使用 JDBC 查询

代码比较简答,直接贴了

    private static Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        String url  = "jdbc:mysql://localhost:3306/db4";
        return DriverManager.getConnection(url, "root", "root");
    }
    /**
     * login in jdbc
     * @param name
     * @param psd
     */
    private void login(String name,String psd){
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            connection = getConnection();
            statement = connection.createStatement();
            // select * from student where studentname = "xxx" and stupsd = "xxx"
            String sql = "select * from student where studentname = '"+name +"' and stupsd = '"+psd+"'";
            resultSet = statement.executeQuery(sql);
            if(resultSet.next()){
                System.out.println("  ---  "+name+" Welcome To Home! ");
            }else{
                System.out.println(" --- error ---");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                connection.close();
                statement.close();
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

特别注意 sql 语句的书写,因为用户名和密码都是字符串类型的,所以需要如上图一样的书写。现在那个账号和密码试一试


这里写图片描述]

发现没 ,没问题。再随便修改下账号


这里写图片描述

从上面比较可以看出这个 jdbc 的查询和 sql 语句没问题。现在用下面的用户名和密码试一试


这里写图片描述

发现没,简直莫名其妙,我们的表中那有这个用户和密码,但是确成功登录了。这技巧无非利用 or 这个关键字,毕竟 a = a 一定为 true,然后再加上 or 那 and 左边 和 右边都是 true 了,这样子 where 后面的限制条件其实已经不起作用了,我们可以将这个 sql 语句在数据库中运行下。

select * from student where studentname = “a” or “a” = “a” and stupsd = “a” or “a” = “a”;

这里写图片描述
发现没 上面的语句 其实和下面一样的

select * from student;

2.3 防备措施
  • 过滤用户输入的数据中是否包含非法字符
  • 分步校验,先使用用户名来查询用户,如果查找到了,再比较密码
  • 使用PreparedStatement

前面两种比较好理解,下面看看这个PreparedStatement的使用

PreparedStatement叫预编译声明,是Statement的子接口

使用它的好处

  • 防止SQL攻击
  • 提高代码的可读性,以可维护性
  • 提高效率

PreparedStatement的使用步骤

  1. 使用Connection的prepareStatement(String sql):即创建它时就让它与一条SQL模板绑定;
  2. 调用PreparedStatement的setXXX()系列方法为问号设置值
  3. 调用executeUpdate()或executeQuery()方法,但要注意,调用没有参数的方法;

现在将代码修改下,如下

            String sql =  "select * from student where studentname = ?";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, name);
            resultSet = preparedStatement.executeQuery();

再用如下代码测试下
这里写图片描述

嗯哼 没问题,现在再使用 有问题的 用户名测试

这里写图片描述

发现没,已经登录不进去了
有朋友可能在想 为什么 PreparedStatement 可以提高效率,其实它已经和 sql 语句绑定了,绑定了 某个 sql 语句的模板,然我们可以使用不用的参数来使用此模板,就是复用 sql 模板。

所以,建议大家在今后的开发中,无论什么情况,都去需要PreparedStatement,而不是使用Statement。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值