目录
6.3 SQL 注入漏洞解决办法(PreparedStatement 方案 )
6 sql注入漏洞
6.1 SQL 注入漏洞核心概念
- SQL 注入漏洞:是程序代码中存在的 “安全缺陷”(比如代码没过滤用户输入、直接拼接 SQL 语句),这是 “根源”。
- SQL 注入:是黑客利用这个 “缺陷” 发起的 “攻击行为”(比如输入 aaa'or'1=1 来篡改 SQL 逻辑),这是 “结果”。
6.2 SQL 注入漏洞产生原因
- 本质逻辑:程序未对用户输入做过滤、验证,直接把用户输入拼接到 SQL 语句里执行,让用户输入能 “篡改原本 SQL 逻辑” 。
- 产生效果:在已知用户名的情况下,输入任意的密码,登陆进去。
- 前提条件
* 先已知用户名
* 后台的程序拼接SQL语句
- SQL注入的漏洞怎么产生?
SQL 注入产生原因是 SQL 语句的拼接,利用 SQL 关键字产生效果。比如:and和or的优先级、注释。sql 语句是在本地拼接好的,问题就出现在了本地字符串拼接
- 代码层面演示(以 Java 代码为例)
假设有登录功能,后台用如下有漏洞的代码处理用户输入:
6 sql注入漏洞
6.1 SQL 注入漏洞核心概念
- SQL 注入漏洞:是程序代码中存在的 “安全缺陷”(比如代码没过滤用户输入、直接拼接 SQL 语句),这是 “根源”。
- SQL 注入:是黑客利用这个 “缺陷” 发起的 “攻击行为”(比如输入 aaa'or'1=1 来篡改 SQL 逻辑),这是 “结果”。
6.2 SQL 注入漏洞产生原因
- 本质逻辑:程序未对用户输入做过滤、验证,直接把用户输入拼接到 SQL 语句里执行,让用户输入能 “篡改原本 SQL 逻辑” 。
- 产生效果:在已知用户名的情况下,输入任意的密码,登陆进去。
- 前提条件
* 先已知用户名
* 后台的程序拼接SQL语句
- SQL注入的漏洞怎么产生?
SQL 注入产生原因是 SQL 语句的拼接,利用 SQL 关键字产生效果。比如:and和or的优先级、注释。sql 语句是在本地拼接好的,问题就出现在了本地字符串拼接
- 代码层面演示(以 Java 代码为例)
假设有登录功能,后台用如下有漏洞的代码处理用户输入:
Scanner inScanner = new Scanner(System.in);
System.out.println("请输入用户名");
String username = inScanner.nextLine();
System.out.println("请输入密码");
String password = inScanner.nextLine();
// 直接拼接用户输入到 SQL 语句,存在漏洞!
String sql = "select * from t_user where username = '"+username+"' and password = '"+password+"'";
search(sql);
这里把用户输入的 username 和 password 直接拼接到 SQL ,没任何过滤,就给了攻击者篡改 SQL 逻辑的机会。
- 攻击案例拆解
- 案例 1:输入 aaa'or'1=1(万能密码攻击 )
- 用户输入:用户名填 aaa'or'1=1 ,密码随意输(比如 123 )。
- 拼接后 SQL:
select * from t_user where username = 'aaa'or'1=1' and password = '123'
- 此时 SQL 的逻辑被强制拆成:
(username = 'aaa') OR ('1=1') AND (password = '123')
- SQL 中 OR 的优先级低于 AND。实际执行顺序等价于:
(username = 'aaa') OR ( ('1=1') AND (password = '123') )
- '1=1' 恒为真,导致where恒为真,数据库返回存在该用户,攻击者成功登录。
- 案例 2:输入 aaa'-- '(注释绕密码验证 )
- 用户输入:用户名填 aaa'-- ' ,密码随意输。
- 拼接后 SQL:
select * from t_user where username = 'aaa'-- ' and password = '123'
- 逻辑篡改:-- 是 SQL 单行注释符,后面 and password = '123' 被注释,SQL 实际执行 select * from t_user where username = 'aaa' ,跳过密码验证,只要有对应用户名记录就登录成功。
6.3 SQL 注入漏洞解决办法(PreparedStatement 方案 )
- 产生 sql 注入的原因:sql 语句是在本地拼接好的,问题就出现在了本地字符串拼接。
- 如何去解决:sql 不在本地进行拼接。
- PreparedStatement 有一个功能—— 在拼接之前对要拼接的数据进行检验 如果遇到了 ' 会在前边加转义字符(\)。比如输入的 1'or'1='1 里的 ' 会被转义成 \' ,最终传入 SQL 的条件变成:
where username = 'aaa' and password = '1\'or\'1\'=\'1'
此时所有的 ' 都只是普通字符串里的引号,不再具备 “闭合字符串、拼接 SQL 逻辑” 的能力,数据库会把 1\'or\'1\'=\'1 当作完整的密码字符串去匹配,而不是 SQL 语法的一部分。
- 核心思路:用 PreparedStatement 接口(Statement 子接口 ),利用预编译 SQL 功能,让用户输入仅作 “数据”,不参与 SQL 语法构建,切断输入篡改逻辑的可能。
- 代码实现步骤
- 编写预编译 SQL:用 ? 占位符代替用户输入的参数(在具体一点的解释见MyBatis 9),示例:
String sql = "select * from t_user where username = ? and password = ?";
- 创建 PreparedStatement 对象:通过 Connection 的 prepareStatement 方法,传入预编译 SQL :
PreparedStatement statement = connection.prepareStatement(sql);
- 给占位符传值:用 setXxxx 方法(按参数类型选,如 setString 、setInt 等 ),根据 ? 位置(从 1 开始 )传值:
statement.setString(1, username);
statement.setString(2, password);
- 执行 SQL:调用 executeQuery(查询 )或 executeUpdate(增删改 ),无需再传 SQL 语句:
ResultSet re = statement.executeQuery(); // 查询示例
- 防注入原理
预编译时,SQL 语法结构已固定,? 只接收 “数据”。就算用户输入特殊字符(如 ' 、OR ),也会被当普通数据处理,不改变 SQL 逻辑,从根源杜绝注入。
完整代码示例(结合登录场景 ):
Scanner inScanner = new Scanner(System.in);
System.out.println("请输入用户名");
String username = inScanner.nextLine();
System.out.println("请输入密码");
String password = inScanner.nextLine();
// 预编译 SQL,用 ? 占位
String sql = "select * from t_user where username = ? and password = ?";
System.out.println("sql=" + sql);
search(sql, username, password);
public static void search(String sql, String username, String password) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=utf8");
// 创建 PreparedStatement,预编译 SQL
PreparedStatement statement = connection.prepareStatement(sql);
// 给 ? 传值
statement.setString(1, username);
statement.setString(2, password);
// 执行查询
ResultSet re = statement.executeQuery();
// 后续处理结果集...
} catch (Exception e) {
e.printStackTrace();
}
}
6.4 总结
- 漏洞产生:程序直接拼接用户输入到 SQL ,让输入能篡改执行逻辑。
- 攻击利用:构造含 SQL 关键字、注释符的输入(如 aaa'or'1=1 、aaa'-- ' ),改变查询条件,绕权限验证。
- 漏洞修复:用 PreparedStatement 预编译 SQL ,固定语法结构,让用户输入仅作数据,彻底解决注入风险 。
914

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



