JDBC 预状态通道(防止SQL 注入)

本文详细介绍了SQL注入的原理,通过一个简单的例子展示了如何通过恶意修改密码实现SQL注入。然后,文章重点讲解了Java中的预状态通道(PreparedStatement)如何防止SQL注入,解释了预状态通道的优势,包括编译SQL语句提高执行效率,以及以字符串方式处理用户输入以增强安全性。最后,给出了使用预状态通道进行登录验证的代码示例。

Java 预状态通道(防止SQL 注入)

SQL注入

就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎 执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据 库,而不是按照设计者意图去执行SQL语句。比如先前的很多影视网站泄露VIP会员密码大多就是通过 WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击。

简单例子:
//正常的 SQL 语句
// 用户名,这里一般是用户输入,我先赋个值
String userName="admin";
// 密码
String passWord="123456";
// SQL 语句
"select * from users where uname='"+userName+"' and password="+passWord;

// 恶意修改
String passWord=" '' or 1=1";
"select * from users where uname='"+userName+"' and password="+" '' or 1=1";
因为 1=1 恒成立,所以上面的语句,无论账号密码是否正确,都会因为 1=1 从而执行成功。
    类似的SQL 注入方式还有很多,为了避免把用户输入当做命令去运行,所以用到 预状态通道

预状态通道在处理值的时候以字符串的方式处理。下面是某登录验证源码

package 预状态通道;

import java.sql.*;
import java.util.Collection;

/**
 * @program: 编程区
 * @description: 预状态通道 用来防止SQL 注入
 * PreparedStatement 预状态通道
 *  对比statement 和 preparedStatement
 *  1. statement属于状态通道,preparedStatement 属于预状态通道
 *  2. 预状态通道会先编译SQL语句,再去执行。比statement 执行效率高
 *  3. 预状态通道支持占位符 '?' ,给占位符赋值时候,从1开始
 *  4. 预状态通道可以防止SQL 注入。  原因是:预状态通道在处理值的时候以字符串的方式处理
 * @author: 白嫖怪AE
 * @create: 2021-12-05 13:13
 **/
public class Demo1 {
    // preparedStatement 该接口扩展了Statement 接口,它提供了一个通用的Statement 对象有两个优点附加功能
    // 此语句可以动态地提供参数
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        PreparedStatement pps = null;

        try {
            //1. 加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            //2. 获取与数据库的连接
            String userName = "root";
            String passWord = "123456";
            // 用来链接 mysql8 的驱动地址
            String url = "jdbc:mysql://localhost:3306/employees?serverTimezone=UTC";
            connection = DriverManager.getConnection(url,userName,passWord);


            //3. 定义SQL 语句,创建预状态通道
            String sql = "select * from users2 where uname=? and password=?";
            pps = connection.prepareStatement(sql);
            // 给占位符 ? 赋值   (下标,赋值)
            // 这里就是 uname pass 就是 用来验证的账号密码, 可以通过Scanner 进行键入值
            String uname="aa";
            String pass = "111";
            pps.setString(1,uname);
            pps.setString(2,pass);
            // 执行SQL
            resultSet = pps.executeQuery();

            // 简单 SQL 注入
            // 说明: 通过拼接 '' or 1=1 。 使得判断用户名、密码语句失效。 从而注入成功
//            String uname="acad";
//            String pass = " '' or 1=1";
//            resultSet = statement.executeQuery("select * from users2 where uname='"+uname+"' and password="+pass);

            //3. 定义SQL 语句,创建状态通道(statement)
//            statement = connection.createStatement();
            // 标准实行sql查询语句
//            resultSet = statement.executeQuery("select * from users2 ");

            
            try {
                if (resultSet.next()){
                    System.out.println("登录成功");
                }else {
                    System.out.println("登录失败");
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            // 这个是 select * from users2 查询语句,遍历显示结果的
//            while(resultSet.next()){
//                // 取出数据 resultSet.getXXX();
//                System.out.println("姓名:"+resultSet.getString("ename")+",工资"+resultSet.getDouble("sal")+",雇佣日期:"+resultSet.getDate("hiredate"));
//            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            //5. 关闭资源
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (connection != null) {
                    connection.close();
                }
                if (statement != null) {
                    statement.close();
                }
                if (pps != null) {
                    pps.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值