引起SQL注入的最根源的问题是没有安全编码规范。
风险
SQL 注入的核心风险
SQL 注入(SQL Injection)是攻击者通过在用户输入中插入恶意 SQL 代码,让应用程序执行非预期的数据库操作,从而窃取、篡改甚至破坏数据。其带来的风险可以分为以下几类,按严重程度排序:
1. 数据泄露(最常见、最直接)
攻击者可以通过构造恶意 SQL 语句,绕过应用程序的权限控制,访问到本不该被查看的数据:
- 窃取敏感信息:获取用户的账号密码(尤其是未加密的明文密码)、手机号、身份证号、银行卡信息、企业核心业务数据(如客户资料、财务数据)等。
- 遍历整个数据库 :通过
UNION SELECT等语句,读取数据库中的所有表名、字段名,进而导出全部数据。示例(恶意输入):
sql
-- 假设登录接口的SQL是:SELECT * FROM users WHERE username='输入值' AND password='输入值'
-- 攻击者输入用户名:' OR 1=1 --
-- 拼接后的SQL变成:SELECT * FROM users WHERE username='' OR 1=1 -- ' AND password='xxx'
-- 注释符(--)会忽略后面的内容,1=1永远为真,直接登录成功并获取所有用户数据
2. 数据篡改与破坏
攻击者不仅能读取数据,还能修改、删除甚至破坏数据:
- 篡改数据:修改用户余额、订单状态、商品价格、个人信息等(比如把商品价格改为 0 元)。示例:
sql
-- 假设修改密码接口的SQL是:UPDATE users SET password='新密码' WHERE id='输入值'
-- 攻击者输入id:1'; UPDATE users SET password='123456' WHERE 1=1 --
-- 拼接后会把所有用户的密码都改为123456
- 删除数据 / 表 :通过
DELETE或DROP TABLE语句删除关键数据(如用户表、订单表),甚至删除整个数据库。示例:
sql
-- 攻击者输入:' ; DROP TABLE users; --
-- 拼接后会直接执行删除users表的操作,导致业务瘫痪
3. 权限提升与服务器控制
如果数据库账户权限过高(比如使用 root/SA 账户连接数据库),攻击者可能进一步控制服务器:
- 提权操作 :通过 SQL 注入执行系统命令(如 MySQL 的
system()、SQL Server 的xp_cmdshell),获取服务器的操作系统权限。 - 植入恶意代码:在服务器上创建后门、植入木马,甚至控制整个服务器,成为黑客的 "肉鸡"。
4. 业务瘫痪与合规风险
- 业务中断:删除核心数据表、修改关键配置,会直接导致应用程序无法运行,企业业务停摆,造成经济损失。
- 合规处罚:在有数据保护法规的地区(如欧盟 GDPR、中国《个人信息保护法》),数据泄露会面临巨额罚款,还会损害企业声誉。
总结
SQL 注入的核心风险可归纳为 3 个关键点:
- 数据层面:敏感数据泄露、数据被篡改 / 删除,是最直接的损失;
- 系统层面:攻击者可提权控制服务器,威胁整个系统安全;
- 业务层面:导致业务瘫痪,还可能引发合规处罚和声誉损失。
对于新手来说,防范 SQL 注入的核心原则是:永远不要信任用户输入,使用参数化查询(预编译语句)而非拼接 SQL 字符串,这是抵御 SQL 注入最有效的方式。
分类
一、按数据交互方式(最核心的分类)
这是根据攻击者输入的数据如何与数据库交互来划分,也是实际测试中最常遇到的类型:
1. 基于报错的 SQL 注入(Error-based Injection)
-
核心特点:攻击者构造恶意 SQL 语句,让数据库执行时抛出明确的错误信息(比如表名、字段名、数据库版本),通过错误提示获取数据库结构和数据。
-
适用场景:应用程序开启了错误回显(比如调试模式下直接显示数据库报错)。
-
示例 :
-- 攻击者输入:' AND (SELECT COUNT(*) FROM information_schema.tables) > 0 -- -- 若数据库表不存在,会抛出"Unknown table"错误,从而确认表是否存在
2. 基于联合查询的 SQL 注入(Union-based Injection)
-
核心特点 :利用 SQL 的
UNION关键字,将攻击者构造的查询结果与原查询结果合并返回,直接获取数据。 -
关键前提 :原 SQL 语句有
SELECT查询且返回结果集(列数、字段类型需与原查询匹配)。 -
示例 :
-- 原SQL:SELECT username FROM users WHERE id='1' -- 攻击者输入:1' UNION SELECT password FROM users WHERE id=1 -- -- 拼接后会同时返回用户名和密码
3. 布尔盲注(Boolean-based Blind Injection)
-
核心特点:应用程序不返回错误信息,也不显示查询结果,仅通过页面 "真 / 假" 的状态(比如 "登录成功 / 失败""内容显示 / 不显示")来判断构造的 SQL 语句是否成立,逐字符猜解数据。
-
适用场景:应用程序做了错误屏蔽,仅返回布尔型结果。
-
示例 :
-- 攻击者输入:1' AND SUBSTRING((SELECT password FROM users WHERE id=1),1,1)='a' -- -- 若页面显示正常,说明密码第一个字符是a;若异常,则不是,逐字符猜解
4. 时间盲注(Time-based Blind Injection)
-
核心特点 :比布尔盲注更隐蔽,攻击者利用
SLEEP()、WAITFOR DELAY等函数,让数据库执行延时操作,通过页面响应时间的长短来判断 SQL 语句是否成立。 -
适用场景:页面无任何状态变化(布尔盲注也无法利用),只能通过响应时间判断。
-
示例(MySQL) :
-- 攻击者输入:1' AND IF(SUBSTRING((SELECT password FROM users WHERE id=1),1,1)='a',SLEEP(5),0) -- -- 若页面响应延迟5秒,说明密码第一个字符是a;否则不是
5. 堆叠查询注入(Stacked Queries Injection)
-
核心特点 :利用分号
;分隔多个 SQL 语句,让数据库依次执行(比如先查询数据,再删除表)。 -
关键前提:数据库支持堆叠执行(如 MySQL、SQL Server,Oracle 默认不支持),且应用程序的数据库驱动允许执行多条语句。
-
示例 :
-- 原SQL:SELECT * FROM users WHERE id='1' -- 攻击者输入:1'; DROP TABLE orders; -- -- 拼接后会先执行查询,再删除orders表
二、按注入位置 / 方式(辅助分类)
除了核心的交互方式,还可以按注入的入口划分,方便定位漏洞:
- GET 注入 :恶意代码通过 URL 的 GET 参数注入(如
http://xxx.com/user?id=1' OR 1=1 --),最常见且易测试。 - POST 注入:恶意代码通过表单、AJAX 等 POST 请求的参数注入(如登录表单的用户名 / 密码输入框),需抓包测试。
- Cookie 注入:恶意代码注入到 Cookie 字段中(应用程序会读取 Cookie 值拼接 SQL),容易被忽略。
- HTTP 头注入:恶意代码注入到 HTTP 请求头(如 User-Agent、Referer),应用程序若用这些值查询数据库则会触发。
三、按执行环境(进阶分类)
- 内联注入(In-band Injection):攻击者的输入和获取的结果通过同一通道(如 HTTP 响应)返回,报错注入、联合查询注入都属于这类(最易利用)。
- 带外注入(Out-of-band Injection/OOB Injection):攻击者通过其他通道获取数据(如 DNS 解析、HTTP 请求),常用于盲注场景(比如将查询结果发送到攻击者的服务器)。
总结
SQL 注入漏洞的核心分类可归纳为 3 个关键点:
- 核心交互类型:报错注入、联合查询注入、布尔盲注、时间盲注、堆叠查询注入(覆盖 80% 以上的实际场景);
- 注入位置类型:GET/POST/Cookie/HTTP 头注入(帮助定位漏洞入口);
- 执行环境类型:内联注入(易利用)、带外注入(隐蔽性高)。
对于新手来说,识别漏洞类型的核心是先看应用程序是否返回错误 / 数据(决定用报错 / 联合查询注入),若无则尝试布尔 / 时间盲注,堆叠查询需关注数据库类型和权限。
出现频率高的是盲注,time盲注,报错注入,union注入。
在不影响正常服务的情况下,拼接查询算最高危害的,接下来就是union。
现在比较好检测的注入有:盲注,time盲注,报错注入等。
SQL注入漏洞的挖掘思路
大的方面是: 爬虫+规则
关于注入的位置:常发生于用户和服务交互处(增删改查操作),ajax,接口等等,
用白盒(结合黑盒)检测报错注入,比较方便。
比如:
PHP+MYSQL扩展默认字符编码为GBK,且代码并未在real_escape_string前强制调用set_charset(real_escape_string是官方推荐的标准安全转义方法),然后研发在代 码 中 使 用 query('set names utf8') 设 置 连 接 字 符 编 码 , 我 们 就 可 以 通 过 info?name=d4rkwind%df\' or sleep(3)-- -&other=xxx方式来注入成功(打破了只要不是"set names gbk"就不会存在半个双字节编码SQL漏洞的误区)。PHP mysql_real_escape_string 对SQL语句中用 户 可 控 的 name 变 量 进 行 了 GBK 编 码 下 的 转 义 , 即 d4rkwind%bf\' or sleep(3)---转义成了d4rkwind%bf\\'orsleep(3)---,总的SQL语句成为selectxxxfromyyywherename='d4rkwind%bf\\'orsleep(3)---' 但 这个"select xxx from yyy where name='d4rkwind%bf\\' or sleep(3)--- -'" 实际上是utf-8的了。所以,成功闭合了。
监测和防御
一、如何监测 SQL 注入漏洞(发现问题)
监测的核心是 "发现已存在的漏洞" 或 "识别正在发生的注入攻击",分为主动检测 (提前找漏洞)和被动监测(实时监控攻击)两类:
1. 主动检测(开发 / 测试阶段)
(1)代码审计(最根本)
- 核心思路 :检查代码中是否存在 SQL 拼接、未过滤的用户输入,重点关注:
- 是否直接拼接用户输入到 SQL 语句中(如
sql = "SELECT * FROM users WHERE id = " + userId;); - 是否使用了不安全的数据库操作方法(如 Java 的
Statement、PHP 的mysql_query); - 是否仅做了简单的字符替换(如只过滤单引号,易被绕过)。
- 是否直接拼接用户输入到 SQL 语句中(如
- 新手实操:优先检查登录、查询、订单等核心功能的代码,标记所有 "用户输入 + SQL 拼接" 的位置。
(2)自动化漏洞扫描
-
工具选择 (新手友好):
- 开源工具:OWASP ZAP、SQLMap(自动化检测 SQL 注入,支持 GET/POST/Cookie 注入);
- 商用工具:AppScan、Burp Suite Pro(适合企业级,误报率低)。
-
实操步骤 :
- 用 ZAP 爬取目标网站的所有接口;
- 对爬取的接口执行 "Active Scan",工具会自动注入测试 payload(如
' OR 1=1 --); - 查看扫描报告,确认高风险的 SQL 注入漏洞。
-
示例(SQLMap 快速检测) :
# 检测GET参数id是否存在SQL注入 sqlmap -u "http://your-site.com/user?id=1" --batch
(3)渗透测试(模拟攻击)
- 由安全人员模拟攻击者的思路,手动测试核心接口(如登录、数据查询):
- 输入特殊字符(
'、"、;、OR 1=1),观察页面是否报错 / 返回异常数据; - 针对盲注场景,测试页面响应时间(如输入
' AND SLEEP(5) --)。
- 输入特殊字符(
2. 被动监测(运行阶段)
(1)日志监控
- 核心思路 :记录所有数据库执行的 SQL 语句和 Web 请求,通过关键词识别异常:
- 监控 Web 访问日志:筛选包含
UNION、SELECT * FROM、DROP TABLE、SLEEP(、--、;等恶意关键词的请求; - 监控数据库日志:开启 MySQL/SQL Server 的慢查询日志、全查询日志,识别非业务预期的 SQL 语句(如批量查询
information_schema表)。
- 监控 Web 访问日志:筛选包含
- 实操 :用 ELK(Elasticsearch+Logstash+Kibana)搭建日志平台,配置告警规则(如 1 分钟内出现 10 次包含
UNION SELECT的请求,立即告警)。
(2)WAF(Web 应用防火墙)实时拦截
- WAF 会实时分析请求内容,识别 SQL 注入特征并告警 / 拦截,是运行阶段的核心监测手段:
- 开源 WAF:ModSecurity(搭配 OWASP Core Rule Set 规则库);
- 商用 WAF:阿里云 WAF、腾讯云 WAF(开箱即用,适合新手);
- 关键:开启 WAF 的日志记录,定期查看拦截的 SQL 注入攻击记录,分析攻击来源和目标接口。
监测方面目前大多都是:日志监控+waf。从厂商角度,日志是最好的资源,日志监控很重要。日志推荐走数据库日志,越是离资源操作近的地方,越是容易做到真正的安全。数据库日志容易解析,语法出错的、语法读Info表的,都明确是黑客嘛,还能帮我们发现SQL注入点。统一的filter也是有效的(如waf),统一filter的目标不是避免漏洞被发现,还是避免漏洞被利用,一个不能被利用的SQL注入,可以认为不是漏洞,脱离了潜在的风险,任何漏洞都不是漏洞。更有效的filter是能读懂访问者的输入(攻击都是来自于输入),如此才能提高准确率,满足大流量互联网公司的诉求,所以,这几年逐渐已经有WAF能初筛似的解析输入,理解语法语义,对于语法错误的可以直接放行。当然,一定要记得是初筛,世界上不同类型数据库不同版本数据库的语法语义都有一定的差异,不可能一个filter能实现所有的解析,太精确的,就只能帮助防御特定版本的数据库了。研发还是得多培训,让他们有安全意识。大部分漏洞,尤其是TOP10漏洞,都是研发的问题,而非设计的问题。
二、如何防御 SQL 注入漏洞(阻止攻击)
防御的核心原则是 **"不信任任何用户输入"**,从底层到上层构建多层防护,以下方法按优先级排序:
1. 核心防御:使用参数化查询(预编译语句)
这是最有效、最根本的防御手段,彻底杜绝 SQL 拼接带来的注入风险,几乎所有编程语言都支持:
-
原理:将 SQL 语句的结构和用户输入分离,用户输入仅作为参数传递,数据库会将参数视为 "数据" 而非 "SQL 代码" 执行。
-
示例(不同语言):
Python + MySQLdb
# 错误写法(拼接SQL,存在注入) user_id = input("请输入用户ID:") sql = f"SELECT * FROM users WHERE id = {user_id}" # 危险! cursor.execute(sql) # 正确写法(参数化查询) sql = "SELECT * FROM users WHERE id = %s" # %s是参数占位符 cursor.execute(sql, (user_id,)) # 参数单独传递,自动转义Java + JDBC
// 错误写法(拼接SQL) String userId = request.getParameter("id"); String sql = "SELECT * FROM users WHERE id = " + userId; // 危险! Statement stmt = conn.createStatement(); stmt.executeQuery(sql); // 正确写法(预编译语句) String sql = "SELECT * FROM users WHERE id = ?"; // ?是占位符 PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, userId); // 设置参数,自动转义 pstmt.executeQuery();PHP + PDO
// 错误写法(拼接SQL) $userId = $_GET['id']; $sql = "SELECT * FROM users WHERE id = $userId"; // 危险! $stmt = $pdo->query($sql); // 正确写法(参数化查询) $sql = "SELECT * FROM users WHERE id = :id"; // 命名占位符 $stmt = $pdo->prepare($sql); $stmt->bindParam(':id', $userId); $stmt->execute();
2. 辅助防御:输入验证与过滤
参数化查询是核心,输入验证可作为补充,进一步降低风险:
-
白名单验证 :只允许符合规则的输入(如用户 ID 只能是数字,手机号只能是 11 位数字),拒绝所有不符合规则的输入。示例(Python):
import re def validate_user_id(user_id): # 只允许数字,长度1-10 if re.match(r'^\d{1,10}$', user_id): return True return False -
避免黑名单过滤 :不要仅过滤
'、OR、SELECT等关键词(易被绕过,如OORR、SeLeCt),白名单优先级远高于黑名单。
3. 权限最小化(降低攻击危害)
即使发生注入,也能限制攻击者的操作范围:
- 数据库账户权限 :应用程序使用的数据库账户仅授予必要权限(如只允许
SELECT/INSERT,禁止DROP/ALTER,禁止访问information_schema); - 禁止使用超管账户:绝对不要用 root(MySQL)、sa(SQL Server)、sysdba(Oracle)连接应用程序。
4. 开启错误屏蔽(隐藏敏感信息)
禁止将数据库原始错误信息返回给用户(如 "Unknown column 'password' in 'field list'"),避免攻击者通过报错获取数据库结构:
- 生产环境关闭调试模式(如 PHP 的
display_errors = Off,Java 的exception.printStackTrace()); - 统一返回自定义错误页面(如 "请求处理失败,请联系管理员")。
5. 使用 ORM 框架(简化防御)
ORM(对象关系映射)框架(如 MyBatis、Hibernate、Django ORM)内置了参数化查询,可减少手动编写 SQL 的风险:示例(MyBatis):
<!-- 正确写法:使用#{}占位符,自动参数化 -->
<select id="getUserById" resultType="User">
SELECT * FROM users WHERE id = #{id}
</select>
<!-- 错误写法:使用${}拼接,存在注入风险 -->
<select id="getUserById" resultType="User">
SELECT * FROM users WHERE id = ${id}
</select>
6. 部署 WAF(最后一道防线)
在应用服务器前端部署 WAF(Web 应用防火墙),实时拦截包含 SQL 注入特征的请求:
- 开源方案:ModSecurity + Nginx,配置 OWASP Core Rule Set 规则库;
- 商用方案:云厂商 WAF(阿里云、腾讯云),无需手动配置规则,适合新手。
总结
监测和防御 SQL 注入漏洞的核心要点:
- 监测层面:主动检测(代码审计 + 自动化扫描)找漏洞,被动监测(日志 + WAF)盯攻击,提前发现问题;
- 防御核心 :优先使用参数化查询 / 预编译语句,彻底杜绝 SQL 拼接风险,这是最有效的手段;
- 辅助防护:白名单输入验证、数据库权限最小化、屏蔽错误信息、部署 WAF,构建多层防护体系。
对于新手来说,记住 "参数化查询是第一原则",只要不手动拼接用户输入到 SQL 中,就能规避 99% 的 SQL 注入风险;同时定期用 SQLMap/ZAP 扫描核心接口,及时发现遗漏的漏洞。
如何能够第一时间发现正在被SQL注入攻击?
日志监控-蜜罐数据-异常报警
三者联动的核心是:
- 日志监控:作为 "全量行为探针",实时采集所有可能的攻击行为数据(Web 请求、数据库执行);
- 蜜罐数据:作为 "攻击验证器",精准标记确认为恶意的 IP / 行为,排除日志监控的误报;
- 异常报警:作为 "实时响应出口",基于日志 + 蜜罐的联动结果,按优先级推送告警,确保第一时间收到。

1. 日志监控(实时采集攻击特征)
目标:实时监控 Web / 数据库日志,捕捉包含 SQL 注入特征的请求。
- 工具 :Linux 自带的
tail+grep; - 配置(监控 Nginx+MySQL 日志):
bash
# 新建监控脚本:sql_inject_monitor.sh
#!/bin/bash
# 定义SQL注入特征关键词
INJECT_PATTERNS="union select|or 1=1|drop table|sleep\(|waitfor delay|--|;|information_schema"
# 实时监控Nginx访问日志(Web层)
tail -f /var/log/nginx/access.log | grep -iE "$INJECT_PATTERNS" | while read line; do
# 提取攻击IP
ATTACK_IP=$(echo $line | awk '{print $1}')
# 记录到临时日志(用于和蜜罐数据联动)
echo "$(date +%s) | WEB | $ATTACK_IP | $line" >> /tmp/sql_inject_suspicious.log
done &
# 实时监控MySQL通用日志(数据库层)
tail -f /var/log/mysql/general.log | grep -iE "$INJECT_PATTERNS" | while read line; do
# 提取攻击IP(MySQL日志需提前配置记录连接IP)
ATTACK_IP=$(echo $line | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" | head -1)
# 记录到临时日志
echo "$(date +%s) | DB | $ATTACK_IP | $line" >> /tmp/sql_inject_suspicious.log
done
bash
chmod +x sql_inject_monitor.sh
nohup ./sql_inject_monitor.sh & # 后台运行,断连不终止
2. 轻量蜜罐部署(精准验证攻击)
目标:模拟脆弱接口,诱捕攻击者,标记 "确认为恶意" 的 IP,避免日志误报。
- 工具:Python Flask(极简蜜罐,5 行核心代码);
- 蜜罐代码(sql_honeypot.py):
python
from flask import Flask, request
import re, os
app = Flask(__name__)
# 注入特征(和日志监控一致)
PATTERNS = r"union select|or 1=1|drop table|sleep\(|--|;"
@app.route('/api/user') # 伪装成业务接口
def fake_api():
attack_ip = request.remote_addr
user_id = request.args.get('id', '')
# 检测到注入特征 → 标记为恶意IP
if re.search(PATTERNS, user_id, re.IGNORECASE):
# 写入恶意IP文件(核心:供告警脚本验证)
with open('/tmp/sql_inject_malicious_ips.txt', 'a') as f:
f.write(f"{attack_ip}\n")
# 记录蜜罐日志
with open('/tmp/sql_inject_honeypot.log', 'a') as f:
f.write(f"{attack_ip} | {user_id}\n")
# 返回虚假数据,迷惑攻击者
return '{"code":200,"data":{"id":"1","name":"test"}}'
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8080) # 暴露在外网可访问的端口
启动蜜罐:
bash
nohup python3 sql_honeypot.py &
(2)蜜罐部署技巧
- 隐藏部署:将蜜罐接口伪装成业务接口(如
/api/user),但仅对外网开放,内网不访问; - 虚假数据:返回的所有数据都是伪造的,避免泄露真实信息;
- 不执行真实 SQL:蜜罐仅检测输入特征,不连接真实数据库,杜绝被利用的风险。
2. 第二步:多维度异常分析与报警(核心联动)
基于 "日志 + 蜜罐" 数据,配置分级异常报警规则,确保第一时间发现攻击:
(1)核心分析规则(在 Kibana 中配置)
|----------------|----------------------------------------------------|------|-------------------------|
| 异常类型 | 检测条件 | 报警级别 | 联动蜜罐验证 |
| 疑似 SQL 注入(日志) | 日志中包含注入特征(UNION SELECT/OR 1=1 等),且请求频率 > 5 次 / 分钟 | 低优先级 | 检查该 IP 是否访问过蜜罐 |
| 确认 SQL 注入(蜜罐) | 蜜罐日志中捕获到该 IP 的注入行为 | 高优先级 | 直接标记为攻击,无需验证 |
| 高危 SQL 操作(数据库) | 数据库执行 DROP/ALTER/TRUNCATE 语句,且非业务白名单 IP | 紧急 | 结合 Web 日志,确认是否为蜜罐捕获的 IP |
(2)报警脚本(联动日志 + 蜜罐数据,Python 示例)
该脚本会同时读取日志和蜜罐数据,实现智能分级报警:
python
import re
import time
import logging
import requests
from elasticsearch import Elasticsearch
# 初始化ES客户端(连接日志存储)
es = Elasticsearch(["http://127.0.0.1:9200"])
# 配置告警渠道(钉钉机器人)
DINGTALK_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=你的token"
# 定义SQL注入特征
INJECTION_PATTERNS = [r"UNION\s+SELECT", r"OR\s+1=1", r"DROP\s+TABLE", r"SLEEP\(", r"--", r";"]
# 第一步:从ES获取疑似攻击的IP(日志维度)
def get_suspicious_ips(time_range="5m"):
# 查询最近5分钟包含注入特征的请求IP
query = {
"query": {
"bool": {
"must": [
{"range": {"@timestamp": {"gte": f"now-{time_range}", "lt": "now"}}},
{"regexp": {"message": "|".join(INJECTION_PATTERNS)}}
]
}
},
"aggs": {"suspicious_ips": {"terms": {"field": "remote_ip.keyword", "size": 100}}}
}
result = es.search(index="sql-security-*", body=query)
# 提取IP和请求次数
suspicious_ips = {}
for bucket in result["aggregations"]["suspicious_ips"]["buckets"]:
ip = bucket["key"]
count = bucket["doc_count"]
suspicious_ips[ip] = count
return suspicious_ips
# 第二步:从ES获取蜜罐捕获的攻击IP
def get_honeypot_attack_ips(time_range="5m"):
query = {
"query": {
"bool": {
"must": [
{"range": {"@timestamp": {"gte": f"now-{time_range}", "lt": "now"}}},
{"term": {"tags": "honeypot"}}
]
}
},
"aggs": {"attack_ips": {"terms": {"field": "remote_ip.keyword", "size": 100}}}
}
result = es.search(index="sql-security-*", body=query)
attack_ips = [bucket["key"] for bucket in result["aggregations"]["attack_ips"]["buckets"]]
return attack_ips
# 第三步:分级发送告警
def send_alert(ip, level, details):
# 告警级别映射
level_map = {
"紧急": {"title": "【紧急】确认SQL注入攻击", "color": "red"},
"高优先级": {"title": "【高优先级】蜜罐确认SQL注入攻击", "color": "orange"},
"低优先级": {"title": "【低优先级】疑似SQL注入攻击", "color": "yellow"}
}
# 构造钉钉消息
msg = {
"msgtype": "markdown",
"markdown": {
"title": level_map[level]["title"],
"text": f"""### {level_map[level]["title"]}
- 攻击IP:{ip}
- 告警时间:{time.strftime("%Y-%m-%d %H:%M:%S")}
- 攻击详情:{details}
"""
}
}
# 发送告警
response = requests.post(DINGTALK_WEBHOOK, json=msg)
if response.status_code == 200:
logging.info(f"告警发送成功:IP={ip}, 级别={level}")
else:
logging.error(f"告警发送失败:{response.text}")
# 主逻辑:联动分析+告警
def main():
# 获取疑似IP和蜜罐攻击IP
suspicious_ips = get_suspicious_ips()
honeypot_ips = get_honeypot_attack_ips()
# 1. 处理蜜罐确认的攻击IP(高优先级/紧急)
for ip in honeypot_ips:
# 检查该IP是否执行了高危操作
if ip in suspicious_ips and suspicious_ips[ip] > 10:
send_alert(ip, "紧急", f"该IP不仅访问蜜罐,还发起{str(suspicious_ips[ip])}次疑似攻击请求,可能执行高危SQL操作")
else:
send_alert(ip, "高优先级", "该IP已被蜜罐捕获,确认执行SQL注入攻击")
# 2. 处理仅日志疑似的IP(低优先级)
for ip, count in suspicious_ips.items():
if ip not in honeypot_ips:
send_alert(ip, "低优先级", f"该IP发起{str(count)}次包含SQL注入特征的请求,暂未被蜜罐捕获,建议观察")
if __name__ == "__main__":
# 每5分钟执行一次联动分析
while True:
main()
time.sleep(300)
bash
chmod +x sql_alert.sh
nohup ./sql_alert.sh &
4. 第四步:自动化处置(可选,进阶)
报警后可联动自动化处置,减少人工介入:
- 临时封禁 IP:通过防火墙(iptables / 阿里云安全组)封禁蜜罐捕获的攻击 IP;
- 限流:对疑似攻击 IP 限制请求频率(如 10 次 / 分钟);
- 标记:将攻击 IP 加入黑名单,后续请求直接拦截。
bash
# 从蜜罐日志中提取攻击IP并封禁
grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" /var/log/honeypot/sql_honeypot.log | sort -u | while read ip; do
# 检查是否已封禁
if ! iptables -L INPUT -n | grep -q "$ip"; then
# 封禁IP(有效期24小时)
iptables -A INPUT -s $ip -j DROP
# 记录封禁日志
echo "$(date) - 封禁SQL注入攻击IP:$ip" >> /var/log/iptables_block.log
fi
done
总结
日志监控 + 蜜罐数据 + 异常报警的核心联动要点:
- 数据层:日志采集全量行为,蜜罐精准标记恶意 IP / 行为,两者互补提升检测准确性;
- 分析层:区分 "疑似攻击(日志)" 和 "确认攻击(蜜罐)",避免误报、漏报;
- 响应层:按攻击确认度配置分级告警 + 自动化处置,确保第一时间发现并拦截攻击。
对于新手来说,可先落地 "日志采集 + 简易蜜罐 + 钉钉告警" 的基础版本,再逐步优化规则和自动化处置,核心是让蜜罐成为 "攻击验证器",让日志监控成为 "全量监控网",两者结合实现精准、及时的 SQL 注入攻击检测。