一、代码漏洞根源
核心危险代码:
// 直接拼接用户输入拼接SQL语句
String sql="select * from password where username='"+username+"'and password='"+password+"'";
使用 Statement + 字符串拼接 SQL ,用户输入的内容会直接拼入 SQL 语句,数据库会执行输入里的 SQL 逻辑,造成注入攻击。
二、注入攻击演示
1. 恶意输入
-
用户名输入:
1111
-
密码输入:
1' or '1' ='1
2. 拼接后最终执行 SQL,恒成立
select * from password where username='1111'and password='1' or '1' ='1'
输出:

三、SQL 能登录成功的核心逻辑
数据库是这样计算的:
where (条件A and 条件B) or 条件C
- 条件 A :
username='1111' - 条件 B :
password='1' - 条件 C :
'1'='1'→ 永远成立!
最终结果:
假 and 假 or 真
= 假 or 真
= 真
只要有一个条件成立,整个 WHERE 就成立! → 直接查到数据 → 登录成功!
本来想让数据库验证:
用户名正确 并且 密码正确
结果被用户改成了:
(用户名正确 并且 密码正确) 或者 1=1
1=1 永远是对的,所以不管用户名密码是什么,都能登录!
五、SQL 注入原理
用户输入的内容里带 SQL 语法,直接破坏了原本的查询逻辑,可以实现绕过密码登录。
- 前端用户输入带有 SQL 语法的特殊字符
- 后端无过滤,直接把输入拼入完整 SQL
- MySQL 识别拼接后的完整 SQL 并执行恶意逻辑
- 实现越权查询、篡改、删除数据
六、高危注入危害输入
- 篡改全部数据
- 直接删除数据表
七、解决方案(杜绝 SQL 注入)
- 放弃
Statement,使用PreparedStatement预编译对象 - 使用
?作为占位符替代字符串拼接 - 预编译会把用户输入全部当成普通文本,不会解析执行 SQL 语法
安全修复代码
package com.qcby.sql;
import java.sql.*;
import java.util.Scanner;
public class LoginUtil {
public static void main(String[] args) throws Exception{
Scanner scanner=new Scanner(System.in);
System.out.println("请输入用户名");
String username=scanner.nextLine();
System.out.println("请输入密码");
String password=scanner.nextLine();
safeLogin(username,password);
}
public static void safeLogin(String username,String pwd) throws Exception{
Class.forName("com.mysql.cj.jdbc.Driver");
String url="你的数据库";
String user="***";
String password="****";
Connection connection= DriverManager.getConnection(url,user,password);
// 使用占位符,禁止字符串拼接
String sql = "select * from password where username=? and password=?";
PreparedStatement pstmt = connection.prepareStatement(sql);
// 给占位符赋值
pstmt.setString(1,username);
pstmt.setString(2,pwd);
ResultSet set=pstmt.executeQuery();
if(set.next()){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
set.close();
pstmt.close();
connection.close();
}
}