数据库操作通常需要执行 SQL 语句,而这些语句往往包含用户输入的数据(如登录表单的用户名、搜索框的关键词等)
如果程序没有对用户输入进行过滤,直接将输入拼接到 SQL 语句中,用户就能通过构造特殊输入,改变 SQL 语句的原本逻辑。
举个例子:
// 接收用户输入的用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
// 直接拼接SQL语句
String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
正常用户输入:
username=admin
,password=123
,生成的 SQL 是:
SELECT * FROM users WHERE username = 'admin' AND password = '123'
但是如果存在恶意输入:
输入 username='' OR '1=1'--
,password
随便填(比如 123
),生成的 SQL 会变成:
SELECT * FROM users
WHERE username = '' OR '1'='1' -- AND password = '随意内容'
--
注释掉后面的 AND
条件,SQL 实际执行:
SELECT * FROM users
WHERE username = '' OR '1'='1'
防御核心:不让用户输入成为 SQL 代码
无论注入逻辑多复杂,防御的关键只有一个:
使用参数化查询,让用户输入永远作为 “数据” 而非 “代码” 执行。
比如 Java 中用 JDBC:
String sql = "SELECT * FROM users WHERE username =? AND password =?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
这样无论用户输入什么,都会被当作字符串处理,无法篡改 SQL 结构,从根本上杜绝注入。