自动化扫描工具在日常安全检测中经常会报出SQL注入漏洞,这类漏洞的核心风险是攻击者可以通过构造恶意SQL语句,非法获取、篡改甚至删除数据库中的敏感数据。了解漏洞报出的原因、掌握验证和修复方法,是安全运维和开发人员的必备技能。

自动化扫描工具常报SQL注入漏洞的原因
自动化扫描工具的原理是向目标系统的参数中注入特定的SQL测试 payload,根据返回结果的特征判断是否存在漏洞,常见报出漏洞的原因有以下几类:
- 参数未做严格的类型校验,比如接收数字ID的参数允许传入字符串内容,给了攻击者注入空间
- 代码中直接拼接用户输入的内容到SQL语句中,没有使用参数化查询或者预编译语句
- 部分特殊字符过滤不彻底,比如只过滤了单引号但没有处理注释符、逻辑运算符等组合 payload
- 扫描工具的误报,部分工具对返回结果的判断规则过于宽泛,会把正常的业务报错识别为漏洞特征
使用SQLMap验证SQL注入漏洞
SQLMap是常用的开源SQL注入检测工具,可以精准验证疑似漏洞是否真实存在,以下是基础的使用步骤:
1. 基础检测命令
假设扫描工具报出的漏洞URL为http://192.168.0.1/test.php?id=1,可以使用以下命令初步检测:
# 检测目标URL是否存在注入点 python sqlmap.py -u "http://192.168.0.1/test.php?id=1" --batch
2. 指定参数和请求方式
如果请求是POST类型,或者需要指定Cookie等头信息,可以使用对应参数:
# POST请求检测,指定表单参数和Cookie python sqlmap.py -u "http://192.168.0.1/login.php" --data "username=admin&password=123" --cookie "sessionid=abc123" --batch
3. 验证结果判断
如果SQLMap输出中存在sqlmap identified the following injection point(s)类似内容,并且明确标注了注入类型,说明漏洞真实存在。如果输出all tested parameters appear to be not injectable,则大概率是扫描工具误报。
SQL注入漏洞的修复方案
根据漏洞的成因,可以采取不同的修复方式,以下是常用的修复方法:
1. 使用参数化查询(预编译语句)
这是最有效的修复方式,不同语言的实现示例如下:
PHP PDO示例
<?php
// 错误写法:直接拼接用户输入
$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];
// 正确写法:使用参数化查询
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll();
?>
Java PreparedStatement示例
// 错误写法:拼接SQL
String sql = "SELECT * FROM users WHERE username = '" + request.getParameter("username") + "'";
// 正确写法:预编译语句
String sql = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, request.getParameter("username"));
ResultSet rs = pstmt.executeQuery();
2. 输入校验和过滤
对用户输入的参数做严格的类型和格式校验,比如数字类型的参数只允许传入整数,字符串类型的参数过滤掉单引号、分号、注释符等危险字符。以下是简单的过滤示例:
<?php
// 过滤SQL注入危险字符
function filter_sql_input($input) {
$danger_chars = array("'", """, ";", "--", "/*", "*/", "union", "select");
return str_replace($danger_chars, "", $input);
}
$username = filter_sql_input($_POST['username']);
?>
3. 最小权限原则
数据库连接的账号只授予必要的最小权限,比如查询接口使用的账号只给SELECT权限,不要使用拥有所有权限的root或sa账号连接数据库,降低漏洞被利用后的损失。
修复后的验证
修复完成后,需要再次使用SQLMap对原来的漏洞点进行检测,确认工具输出不存在注入点,同时可以手动构造常见的SQL注入 payload 测试,确保漏洞已经被彻底修复。