[数据库]JDBC&SQL注入攻击&预编译SQL

SQL注入攻击

拼接SQL语句存在SQL注入攻击

方式

表现为通过输入aaa' OR '1'='1改变后台SQL语句语义,不需要正确密码即可获取数据资料

比如以下登录代码中:

public class JDBCDemo6 {
    public static void main(String[] args) {
        System.out.println("欢迎登录");
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名");
        String username = scanner.nextLine();
        System.out.println("请输入密码");
        String password = scanner.nextLine();

        try (
                Connection connection = DBUtil.getConnection();
        ){
            Statement statement = connection.createStatement();
           
            String sql = "SELECT id,username,password,nickname,age " +
                         "FROM userinfo " +
                         "WHERE username='"+username+"' " +
                         "AND password='"+password+"'";
            ResultSet rs = statement.executeQuery(sql);
            if(rs.next()){//根据该用户名和密码作为过滤条件查询到记录,说明登录成功
                String nickname = rs.getString("nickname");
                System.out.println("登录成功!欢迎回来:"+nickname);
            }else{
                System.out.println("登录失败,用户名或密码错误");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}

sql语句WHERE筛选条件正常语义判断为满足正常用户名和密码正确可登录,不满足失败

 String sql = "SELECT id,username,password,nickname,age " +
                         "FROM userinfo " +
                         "WHERE username='"+username+"' " +
                         "AND password='"+password+"'";
            ResultSet rs = statement.executeQuery(sql);

此时我正常输入不满足的值,登录失败。

 如果注入攻击输入,即:

 登录成功了,并获取到了数据。

因为它此时的SQL语句是:

SELECT id,username,password,nickname,age
FROM userinfo
WHERE username='aaa' AND password='aaa' OR '1'='1'

AND优先级比OR高,那么WHERE中为A OR B满足其中一条就可通过,而‘1’=‘1’是恒定为true的,所以WHERE失效。

针对这个问题,JAVA提供了预编译。

预编译SQL

当SQL中含有变量时,通常我们不能直接拼接SQL语句,因为这存在SQL注入攻击。

  • 我们可以使用预编译SQL语句,在预编译SQL语句中变量部分先用"?"代替。
  • 然后将整条预编译SQL传给数据库使其生成执行计划(此时数据库就已经确定了SQL语义),然后等待我们传入"?"对应的值然后执行这条SQL。
  • 此时无论我们传入的值是什么,数据库都仅会将其当做值看待,并不会在改变SQL语义。

例如:

为登录逻辑编写预编译SQL语句

 SELECT id,username,password,nickname
 FROM userinfo
 WHERE username=? AND password=?

先将这个SQL发送给数据库,此时数据库就理解了这个SQL的语义。但是还不能执行,因为缺少?表达的两个值

当我们需要执行这条SQL时,我们仅需要再传入两个值给数据库即可:

public class JDBCDemo7 {
    public static void main(String[] args) {
        try (
                Connection connection = DBUtil.getConnection();
        ){
            String sql = "SELECT id,username,password,nickname,age " +
                         "FROM userinfo " +
                         "WHERE username=? AND password=?";
            //创建PrepareStatement是要现将预编译SQL传入,此时该方法会将该SQL传给数据库
            PreparedStatement ps = connection.prepareStatement(sql);
            //为?指定值
            //给第一个"?"(用户名的值)指定值,由于用户名为VARCHAR类型,因此这里要设定字符串
            //参数1:第几个"?".下标从1开始.
//            ps.setString(1,"张三");
//            ps.setString(2,"123456");
            ps.setString(1,"abbaba");
            ps.setString(2,"a' OR '1'='1");//不会改变语义,仅将其当做密码的值看待
            //执行该DQL,此时不需要再传入SQL语句了.执行时会将上述设置的"?"表达的值传递给数据库
            ResultSet rs = ps.executeQuery();
            if(rs.next()){
                String nickname = rs.getString("nickname");
                System.out.println("登录成功!欢迎回来:"+nickname);
            }else{
                System.out.println("登录失败,用户名或密码错误");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }


    }
}

代码思路:

获得连接对象connection

通过连接对象获得ps预编译执行对象,并在此时将预编译SQL传入(没有预编译时是在调用执行对象方法是传入)

调用setString给?赋值

在调用执行方法ps.executeQuery()执行(此时不用传SQL了)

判断是否有满足WHERE语句的记录并输出

同理在其他语言中也是如此,比如DML语言中:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值