iptables的--string模块无法可靠过滤SQL关键字,因其仅能匹配单个IP包内连续字节,而真实SQL流量常被TCP分段、二进制封装、TLS加密或编码变形,导致匹配失效。

iptables 的 --string 模块不能可靠过滤包含 SQL 关键字的报文——这不是配置问题,而是能力边界决定的。
它最多只能在单个 IP 包的原始载荷里找连续字节,而真实 SQL 流量(尤其是 HTTP POST、MySQL 协议、TLS 加密流)根本不符合这个前提。
--string 在 SQL 场景下为什么几乎必然失效
- HTTP 请求中的
SELECT * FROM users WHERE name='admin'很可能被拆成多个 TCP 分段,关键词被截断在不同包里,--string对每个包单独扫描,永远匹配不全 - MySQL 协议是二进制格式,没有明文关键字;即使启用旧版明文认证,用户名/密码也封装在协议头后,
--string无法跳过长度字段或序列号去定位有效载荷 - HTTPS 流量中所有应用数据(包括含 SQL 的 AJAX 请求)都是 TLS 密文,
--string "DROP TABLE"实际匹配的是随机密文,命中纯属巧合 - URL 编码(
delete%20from)、空格替换(SEL ECT)、大小写混用(SeLeCt)都会让基于bm或kmp算法的匹配完全失效 - 启用
--string会强制禁用连接跟踪快速路径,高并发下吞吐骤降,且规则位置稍有偏差(比如没加-m conntrack --ctstate ESTABLISHED,RELATED)就可能漏掉响应包
如果仍要硬上 --string,必须满足这 3 个苛刻条件
- 目标服务必须是未加密、未压缩、单包可承载完整请求的明文协议(例如:某内网调试用的裸 TCP SQL 控制台,端口非 3306)
- 关键字必须以固定编码、固定大小写、无分隔干扰出现(如强制要求客户端发
select全小写且前后带空格) - 规则必须绑定到正确链和状态,例如:
iptables -A INPUT -p tcp --dport 9999 -m conntrack --ctstate ESTABLISHED -m string --string " select " --algo bm -j DROP
注意:--algo bm比kmp更快但更脆弱;--icase在部分内核版本不支持,勿盲目添加
真正能拦截 SQL 关键字的替代路径
-
Web 层:用 Nginx 的
ngx_http_rewrite_module或 Apachemod_security解析 HTTP 请求体,匹配args或request_body -
数据库代理层:部署
mysql-proxy或ProxySQL,在协议解析后检查 query 字段,支持正则、语法树分析 -
应用层防御:强制使用参数化查询(
PreparedStatement、psycopg2.execute()),从源头消灭拼接风险 -
网络层 DPI:用
nDPI+iptables配合 TPROXY 重定向,或直接上Zeek做会话级检测(但已超出 iptables 范畴)
真正的 SQL 流量控制点不在 netfilter 的包级钩子,而在协议栈更上层。把 --string 当 SQL 防火墙用,就像用尺子测体温——工具错位,结果注定不可信。











