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();
}
}
}
}

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

被折叠的 条评论
为什么被折叠?



