SQL注入攻击的核心是利用应用未对用户输入做严格过滤的漏洞,将恶意SQL代码片段插入到请求参数中,让后端数据库执行非预期的操作。应用服务器的访问日志会记录每一次请求的详细信息,包括请求时间、请求路径、参数内容、来源IP、响应状态码等,这些信息是识别SQL注入迹象的核心依据。

SQL注入的常见特征
要识别SQL注入,首先需要了解恶意请求的典型特征,这些特征会直接体现在访问日志中:
- 请求参数中包含SQL语法关键字,比如
SELECT、UNION、OR、AND、INSERT、DROP等,且这些关键字不是正常业务需要的。 - 参数中出现SQL注释符号,比如
--、/*、*/,用来截断原有SQL语句的逻辑。 - 参数包含单引号、双引号等字符串界定符,用来闭合原有SQL语句中的字符串参数,比如
id=1' OR '1'='1。 - 出现数据库特有的函数或语法,比如
version()、database()、sleep()、load_file()等,这些是攻击者探测数据库信息的常用手段。 - 同一IP短时间内发送大量包含异常参数的请求,属于自动化注入工具的扫描行为。
访问日志中需要关注的字段
不同应用服务器的访问日志格式略有差异,但核心字段基本一致,分析时需要重点关注以下内容:
| 字段名称 | 说明 | 分析价值 |
|---|---|---|
| 请求时间 | 请求发起的时间戳 | 判断是否为批量扫描,同一时间段大量异常请求大概率是攻击 |
| 请求行 | 包含请求方法、URL路径、参数、协议版本 | 直接查看参数中是否包含SQL注入特征内容 |
| 来源IP | 发起请求的客户端IP | 定位攻击来源,判断是否为单一IP持续攻击 |
| 响应状态码 | 服务器返回的HTTP状态码 | 500等错误状态码可能说明注入语句触发了数据库报错 |
| User-Agent | 客户端的浏览器或工具标识 | 出现sqlmap、havij等扫描工具标识可直接判定为攻击 |
日志分析实操步骤
1. 提取可疑请求
首先可以通过关键字过滤快速筛选出可能包含SQL注入的请求,以Nginx访问日志为例,日志默认格式为:
$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"
可以使用grep命令过滤包含SQL关键字的请求:
# 过滤包含union关键字的请求
grep -i "union" /var/log/nginx/access.log
# 过滤包含单引号且包含or关键字的请求
grep -E "'.*or.*" /var/log/nginx/access.log
# 过滤包含sleep函数的请求
grep -i "sleep(" /var/log/nginx/access.log
2. 验证请求是否为注入攻击
提取到可疑请求后,需要进一步验证参数是否真的构成注入风险,比如看到请求/api/user?id=1' OR 1=1--,可以查看对应的响应状态码和返回内容:
- 如果响应状态码为200,且返回了超出预期的用户数据,说明注入成功。
- 如果响应状态码为500,且返回内容包含数据库报错信息,说明注入语句触发了异常,属于攻击尝试。
- 如果响应正常且返回内容和正常请求一致,可能是业务本身参数包含相关字符,需要结合业务场景判断。
3. 统计攻击特征
对筛选出的可疑请求做进一步统计,明确攻击的影响范围:
# 统计攻击来源IP top10
grep -i "union" /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
# 统计攻击请求的URL分布
grep -i "union" /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn
常见误判场景说明
分析日志时需要注意区分正常业务请求和SQL注入攻击,避免误判:
- 部分业务场景的参数本身可能包含SQL相关关键字,比如搜索功能允许用户输入
select作为搜索词,需要结合参数位置判断,如果是搜索参数且做了转义处理则属于正常请求。 - 部分合法工具的User-Agent可能包含类似扫描工具的字符,需要结合请求内容综合判断,不能仅通过User-Agent直接判定。
- 数据库报错可能是业务代码本身的bug导致,需要查看报错内容是否和注入语句相关,再确认是否为攻击。
防护建议
识别到SQL注入迹象后,除了及时封禁攻击IP,还需要从根源上做防护:
- 所有用户输入的参数都做严格的类型校验和特殊字符转义,避免恶意SQL片段被拼接执行。
- 使用参数化查询或者预编译语句,从代码层面杜绝SQL注入的可能。
- 定期分析访问日志,设置异常请求告警规则,比如同一IP短时间内出现多个包含SQL关键字的请求时自动触发告警。
- 限制数据库账号的权限,避免使用root等最高权限账号连接业务数据库,降低注入攻击的破坏范围。