【很有料】浅析Statement和PreparedStatement,SQL注入

一、SQL注入

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

上述语句摘自百度百科,可能对于有些人来说晦涩难懂,那么我举个最简单的例子,来体验这一过程;

假设有一个登录表单,后台数据校验sql为select * from user where username = 'XXX' and pasword = 'XXX',XXX为传入的用户名和密码,根据sql返回的结果判断登录是否成功;(方便解释,简单处理)

这条sql是预先拼接好然后提交给数据库执行的,假设我们把password的内容改为1' or '1' = '1注意里面的单引号!如果登录名为caojiantao,那么最终生成的sql便是:

select * from user where username = 'caojiantao' and pasword = '1' or '1' = '1'

!!这样一来不用知道用户caojiantao的密码也能够登录成功了,更有甚者,在密码处输入"1';drop table user;",直接删除了数据表,十分的危险。

这就是一个最简单sql注入的例子,输入包含sql命令的内容,欺骗服务器执行破坏数据。

二、Statement

JDBC核心接口,对象用于将SQL语句发送到数据库中。一个简单的demo演示Statement的使用;

    public static void main(String[] args) {
        // 数据库配置
        String url = "jdbc:mysql://127.0.0.1/ssm";
        String name = "com.mysql.jdbc.Driver";
        String user = "root";
        String pasword = "Cjt00382114.";
        // 登录账号密码
        String username = "caojiantao";
        String pswd = "123";
        // 拼接sql
        String sql = "select * from user where username = '" + username + "' and pasword = '" + pswd + "'";
        try {
            // jdbc操作
            Class.forName(name);
            Connection connection = DriverManager.getConnection(url, user, pasword);
            // Statement
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(sql);
            while (resultSet.next()){
                System.out.println(resultSet.getString("nickname"));
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }

代码很简单,判断用户名和密码是否匹配,匹配则输出用户的nickname昵称;

根据上面sql注入的问题,我们试着把pwd传入1' or '1' = '1,前面的1可以随便填,运行程序可以发现输出了用户昵称曹建涛,说明sql注入成功,那么,我们该怎么避免呢?

三、PreparedStatement

采用字符串匹配?筛选sql命令字符串?没那么麻烦,JDBC已经有现成的处理方案了,那就是PreparedStatement

PreparedStatement继承自Statement,字面可译为声明,强调一个预,内部包含一个预编译的sql语句,参数采用占位符?进行填充,还是看一段代码体会下;

    public static void main(String[] args) {
        // 数据库配置
        String url = "jdbc:mysql://127.0.0.1/ssm";
        String name = "com.mysql.jdbc.Driver";
        String user = "root";
        String pasword = "Cjt00382114.";
        // 登录账号密码
        String username = "caojiantao";
        String pswd = "123";
        String preSql = "select * from user where username = ? and pasword = ?";
        try {
            // jdbc操作
            Class.forName(name);
            Connection connection = DriverManager.getConnection(url, user, pasword);
            // PreparedStatement
            PreparedStatement preparedStatement = connection.prepareStatement(preSql);
            preparedStatement.setString(1, username);
            preparedStatement.setString(2, pswd);
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()){
                System.out.println(resultSet.getString("nickname"));
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }

我们可以修改pwd内容为1' or '1' = '1,运行程序没有任何输出,说明PreparedStatement有效地避免了sql注入问题;

因为SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,对应的执行计划也会缓存下来并允许数据库已参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1'也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令,如此,就起到了SQL注入的作用了!

上述摘自java中预处理PrepareStatement为什么能起到防止SQL注入的作用??!!

因为是继承关系,因而Statement具备的PreparedStatement全都有,而且PreparedStatement还具备独有的预处理功能,相比StatementPreparedStatement好处有三:

  1. 提高代码的可读性,便于维护;
  2. 提高了sql执行效率;
  3. 增强了安全性,避免sql注入;

四、花絮——myBatis的 # 和 $

# 相当于对数据 加上 双引号,$ 相当于直接显示数据。

一句话言简意赅。分条陈述:

  1. # 能够sql注入问题,$ 不行;
  2. $ 用于传入数据库对象,例如表名;
  3. 能用 # 就不要使用 $;




转自:https://www.jianshu.com/p/643866408bb7

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值