时间盲注防御需数据库执行层与应用逻辑层协同:强制参数化查询、限制高危函数权限、统一响应时间干扰、基于耗时行为的日志监控。

时间盲注无法被前端界面或日志直接识别,防御必须从数据库执行层和应用逻辑层双管齐下——单靠WAF或输入过滤基本无效。
用参数化查询彻底切断拼接路径
时间盲注依赖于用户输入被原样嵌入SQL语句中,只要字符串拼接存在,SLEEP()、IF()、WAITFOR DELAY就可能被执行。参数化查询(预编译)强制将数据与语句结构分离,数据库引擎不会把参数值当作代码解析。
- PHP 中禁用
mysql_query()+ 字符串拼接,改用 PDO 的prepare()+bindValue() - Java 中弃用
Statement,改用PreparedStatement并绑定setString()等方法 - Python 中避免
cursor.execute("SELECT * FROM t WHERE id = '" + user_id + "'"),改用cursor.execute("SELECT * FROM t WHERE id = ?", (user_id,)) - 注意 ORM 并不自动免疫:Django 的
raw()、SQLAlchemy 的text()仍可触发漏洞,必须人工确认是否带参数绑定
限制数据库函数权限与禁用高危函数
即使注入点存在,若数据库账户无权调用延迟函数,SLEEP()、pg_sleep()、WAITFOR DELAY 会直接报错或静默失败,攻击链立即中断。
- MySQL:回收普通应用账号的
EXECUTE权限,显式REVOKE EXECUTE ON PROCEDURE *.*;删除或重命名sys_eval等扩展函数(如存在) - PostgreSQL:确保应用连接不使用
postgres超级用户,pg_sleep()在普通用户下默认可用,但可通过security definer函数控制调用入口 - SQL Server:禁用
sp_execute_external_script,限制WAITFOR使用场景,生产环境关闭xp_cmdshell - 关键点:
SELECT SLEEP(1)和SELECT IF(1=1, SLEEP(1), 0)都需要函数执行权限,不是“语法合法就能跑”
统一响应时间 + 主动延迟干扰
时间盲注成立的前提是攻击者能稳定区分“快响应”和“慢响应”。如果所有请求都固定耗时 800ms,或在正常逻辑后主动加一段随机抖动(如 0–300ms),SLEEP(5) 就失去判别意义。
- Web 框架层可在中间件统一设置最小响应时间(如 Flask 的
after_request加time.sleep(0.8)),掩盖真实执行差异 - 更稳妥的做法是引入 jitter:对非敏感接口,在返回前执行
time.sleep(random.uniform(0.1, 0.4)) - 注意:不能只对错误路径加延迟,否则反而暴露了条件分支——必须对所有路径一视同仁
- 此法无法替代参数化,仅作为纵深防御补充;高精度计时(如 NTP 同步客户端)仍可能绕过,但已大幅提高攻击成本
日志与监控要捕获延迟异常而非 SQL 内容
传统 WAF 规则匹配 SLEEP、WAITFOR 效果差:大小写变形、编码绕过、嵌套括号都容易逃逸。真正有效的检测是行为维度——不是看“说了什么”,而是看“花了多久”。
- 记录每个请求的 DB 查询耗时,对超过 P95 延迟阈值(如 1200ms)且非缓存命中、非大数据导出的请求打标告警
- 聚合分析:连续出现多个
id=xxx' AND IF(..., SLEEP(5), 0)--类似模式的请求源 IP,即使每次 payload 不同,其响应时间分布高度一致 - 不要依赖
error_log或access_log做规则匹配——时间盲注通常不产生错误,日志里只有一行 200 OK - 最易忽略的一点:数据库慢查询日志(如 MySQL 的
slow_query_log)必须开启,且long_query_time设为 0.5s 级别,否则根本看不到SLEEP(5)这类“合法但恶意”的慢语句











