sql注入检测需以行为分析为主、规则匹配为辅,通过clickhouse建立用户/接口基线,标准化sql指纹并实时聚合异常模式,结合业务白名单与冷启动策略降低误报。

SQL注入检测不能只靠规则匹配
行为分析是补位,不是替代。WAF或正则规则对变形编码、注释绕过、时间盲注几乎失效,SELECT 1 FROM users WHERE id=1 AND SLEEP(5) 这类请求本身语法合法,但执行模式异常——这才是行为分析要抓的点。
关键不是“有没有UNION或SELECT”,而是“这个用户平时只查user_id,今天突然高频发带information_schema的请求”。
- 必须建立每个用户/接口的基线:平均QPS、常见参数长度、典型SQL模板(如
WHERE status = ?)、响应延迟分布 - 跳过静态规则已拦截的流量,行为模型只处理“通过了语法校验但行为可疑”的请求
- 注意
Content-Type: application/json里藏SQL的情况——解析body时别漏掉params字段嵌套的恶意字符串
用ClickHouse做实时SQL行为聚合最省事
日志写入快、窗口函数成熟、支持groupArray()拼历史序列,比Elasticsearch更适合做“单个IP最近10次请求的SQL指纹对比”。
示例:从Nginx或应用层埋点采集client_ip、uri、sql_hash(用xxHash64对标准化后的SQL去空格小写哈希)、response_time,每分钟跑一次检测:
SELECT client_ip FROM access_log WHERE event_time > now() - INTERVAL 1 MINUTE GROUP BY client_ip HAVING avg(response_time) > 2000 AND uniqExact(sql_hash) >= 5 AND max(length(uri)) - min(length(uri)) > 100
-
sql_hash必须标准化:剔除数字字面量、统一空格、转小写,否则WHERE id=1和WHERE id=999算两个指纹 - 别直接用
count()代替uniqExact(),攻击者会混入正常查询稀释统计 - ClickHouse的
timeWindow函数比now()-INTERVAL更准,避免因节点时钟漂移漏数据
误报集中在登录接口和搜索框
用户输' OR '1'='1测试系统反应,或搜索词含AND、OR被当成注入,这类场景必须加业务白名单。
- 对
/login、/search等接口,单独配置宽松阈值:只告警不拦截,且要求连续3次才触发 - 提取
Referer和User-Agent做辅助判断——爬虫头+SQL关键词组合,可信度远高于浏览器发起的相同请求 - 检查
Content-Length是否异常大,SELECT * FROM (SELECT ...)嵌套深的攻击常伴随超长payload
行为模型上线后最麻烦的是冷启动
没历史数据时,所有新用户都是“异常”——模型会把第一次登录当成试探性扫描。
- 上线前先用7天脱敏日志跑离线训练,生成初始基线,而非从零开始实时学习
- 给内部测试账号打标签
is_internal=1,这类流量不参与模型更新,避免把调试行为学成正常模式 - 保留原始SQL样本的
sample_id,一旦误拦,能快速反查是哪个特征(比如stddev(response_time)突增)导致的
真正难的不是识别那条UNION SELECT @@version,而是区分“运维在查库”和“黑客在探库”——这两者SQL长得一样,差别在时间、频次、上下文,得靠数据喂出来,没法抄配置文件。










