数据库访问风控拦截恶意非法请求,本质上是在数据库外围或驱动层建立一道实时判断请求合法性的闸门。很多团队把精力全部放在SQL注入和账号权限上,却忽略了大量非法请求根本不需要走到SQL执行阶段,在连接建立、语句解析、参数结构层面就已经可以被识别并拦截。真正有效的风控不是等数据库报错后再去翻日志,而是让恶意请求在触碰核心数据前就被丢弃。
数据库请求的风险模型要从三个维度同时看:请求来源、请求形态、请求目标。来源包括IP、主机名、应用标识、客户端工具特征;形态包括SQL语句结构、参数长度、执行频率、语法复杂度;目标包括库、表、列、函数、系统存储过程。单独看任何一个维度都容易误判,只有把三者组合起来,才能区分正常业务高峰和恶意扫描、区分复杂报表和拖库行为。
先识别非法请求的典型特征恶意非法请求通常不是随机出现的,它们有非常明显的模式。第一种是扫描型请求,表现为短时间内对系统表、元数据表、默认表名进行枚举,例如连续查询information_schema、sys.tables、mysql.user、pg_catalog等对象。第二种是注入型请求,SQL语句中包含大量拼接特征,比如单引号异常闭合、UNION SELECT、WAITFOR DELAY、SLEEP函数、LOAD_FILE、INTO OUTFILE等关键字。第三种是暴力型请求,对同一登录入口或查询接口高频重试,参数变化有规律但失败率极高。第四种是越权型请求,请求的目标表或列与应用当前会话权限不匹配,比如普通业务账号突然查询整张用户表或资金流水表。
识别这些特征不能只靠正则表达式。正则能挡住一部分已知攻击,但对编码绕过、注释混淆、大小写变形、等价函数替换的识别率很低。更可靠的方式是把SQL解析成抽象语法树,在语法树层面判断请求是否访问了不该访问的对象、是否出现了危险函数调用、是否包含异常的子查询嵌套或联合查询结构。
在数据库驱动层做拦截比在应用层更可靠很多开发团队习惯在应用代码里加过滤和校验,但应用层拦截有两个致命问题。第一是覆盖不全,一个公司可能有几十个微服务、多个语言栈、不同团队维护,只要有一个服务漏掉校验逻辑,数据库就暴露了。第二是应用层拿不到数据库的真实执行上下文,无法判断一个SQL语句最终会扫描多少行、触发什么权限检查、访问哪些物理文件。
数据库驱动层拦截的优势在于,所有请求都必须经过驱动才能到达数据库。可以在驱动和数据库之间部署一层代理,或者使用支持扩展的数据库中间件。这个中间层负责解析请求、提取特征、匹配策略、记录行为、决定放行或阻断。对于MySQL系可以使用ProxySQL或自研的MySQL协议代理,对于PostgreSQL可以使用PgBouncer扩展或自定义协议过滤,对于SQL Server可以基于Always On监听层做流量镜像和拦截。
构建请求画像和基线模型风控拦截不能只靠静态规则,静态规则容易被绕过,也容易误杀正常业务。更有效的方式是给每个应用、每个数据库账号、每个来源IP建立请求画像。画像包括正常访问的表集合、列集合、SQL类型分布、平均查询复杂度、执行时间区间、请求频率曲线、活跃时间段。
基线模型建立后,风控系统可以实时比对当前请求与基线的偏离程度。例如某个应用账号过去30天从未访问过用户手机号字段,今天突然出现大量SELECT phone FROM users的请求,即使SQL语法完全合法,也应该被标记为高风险并触发拦截或二次认证。又比如某个报表任务每天凌晨2点执行一次,某天下午3点突然以相同账号执行相同SQL,来源IP却变了,这种时间偏离和来源偏离叠加,同样需要拦截。
偏离检测的算法不需要太复杂,实践中用统计分布和阈值就能解决大部分问题。对数值型特征可以计算历史均值和标准差,当前值偏离超过三倍标准差就告警。对类别型特征可以计算历史出现频率,出现从未见过的表名、列名、函数名就加分。对序列型特征可以计算时间间隔和频率变化,单位时间请求量突然放大就触发限流。
拦截策略要分层,不能一刀切直接阻断所有可疑请求会造成大量误伤,影响业务连续性。风控拦截应该设计成多级响应机制。第一级是记录和标记,对轻微偏离基线的请求放行,但记录完整上下文,包括原始SQL、参数、来源、时间、会话信息。第二级是挑战验证,对中等风险请求返回延迟或要求应用携带更严格的身份令牌,比如要求重新认证、要求带一次性签名。第三级是限流降级,对高频可疑请求限制其并发数和每秒请求数,让扫描行为变得极慢但又不完全断开。第四级才是完全阻断,对明确命中攻击特征的请求直接断开连接并封禁来源一段时间。
分层拦截的关键在于策略引擎要支持动态调整。安全团队可以在发现新型攻击时快速下发临时规则,而不用重启数据库或修改应用。策略引擎最好支持基于表达式的规则配置,例如:当来源IP信誉分低于阈值且SQL中包含UNION SELECT且目标表为系统表时,执行阻断动作。规则之间可以组合,也可以设置优先级和有效期。
处理加密和混淆流量数据库访问风控面临的一个现实挑战是流量加密。很多生产环境要求数据库连接使用TLS,中间层代理如果只是简单转发,就无法解析加密后的SQL内容。解决这个问题有两种路线。第一种是在代理层终结TLS,代理持有数据库证书私钥,解密后再重新加密转发给数据库。这种方式能获得完整的明文SQL,但代理本身成为敏感节点,需要严格加固。第二种是使用数据库原生的审计插件或扩展,在数据库内部解析请求并输出结构化日志,风控系统消费这些日志做准实时分析。这种方式的延迟比代理层稍高,但实现成本低,不需要改动网络架构。
对于使用了应用层加密或自定义协议的情况,数据库层能看到的内容有限,此时需要结合应用日志和网关日志做关联分析。比如从API网关获取请求参数,从数据库审计日志获取SQL执行记录,通过请求ID或时间窗口把两者关联起来,判断某个HTTP请求最终触发了什么数据库操作,是否存在参数篡改或越权访问。
防止误伤正常业务的几个关键点风控系统上线初期最容易出现的问题就是误伤。避免误伤的第一原则是观察期足够长,至少收集两周以上的真实流量,覆盖完整的业务周期,包括月初月末、节假日、促销活动等特殊时段。第二原则是白名单机制要精细,不能只按IP或账号加白,要细化到应用标识、SQL模板、表列范围、时间窗口的组合。第三原则是拦截动作要可逆,阻断的连接可以快速恢复,封禁的IP可以一键解封,所有拦截记录都可以追溯到具体规则和特征值。
还有一个容易被忽略的点是,数据库内部的任务和存储过程也会产生请求。这些请求可能来自定时任务、触发器、复制进程、备份工具。风控系统必须能区分外部应用请求和内部系统请求,避免把数据库自己的维护操作当成攻击拦截。通常可以通过来源主机名、进程名、连接属性中的程序标识来区分。
实时告警和事后追溯同样重要拦截只是第一道防线,完整的数据库访问风控还需要实时告警和事后追溯能力。实时告警要能推送到安全运营团队,告警内容不能只写“发现可疑SQL”,而要包含具体风险类型、来源IP、目标库表、SQL摘要、命中规则、建议处置动作。告警渠道可以对接企业微信、钉钉、邮件、SIEM平台。
事后追溯依赖完整的审计记录。每一条被拦截或放行的请求都应该保存结构化日志,至少保留90天。日志字段包括时间戳、会话ID、来源IP、应用标识、数据库账号、数据库名、SQL模板、完整参数、执行时长、影响行数、风控评分、最终动作。这些数据不仅用于安全事件调查,还能用于定期复盘策略效果,发现新的攻击趋势。
一个可落地的拦截规则示例下面给出一个基于SQL特征和频率的组合拦截逻辑,可以直接在中间件或风控引擎中实现:
规则名称:防拖库联合查询拦截 触发条件: 1. SQL语法树中存在UNION查询节点 2. UNION后的查询访问了用户表或订单表 3. 当前会话在最近60秒内执行过information_schema查询 4. 当前来源IP在最近5分钟内新建连接数超过20 动作: 阻断当前请求,断开连接,封禁来源IP 30分钟 记录完整SQL和会话上下文 推送高危告警
这个规则的核心在于把多个弱特征组合成强特征。单独出现UNION查询可能是正常的分页合并,单独查询information_schema可能是开发工具在查看表结构,单独连接数高可能是应用重启。但四个条件同时出现,基本可以判定为恶意拖库行为。
数据库访问风控拦截恶意非法请求,最终比拼的不是规则数量,而是对业务数据库真实访问模式的了解程度。越了解正常请求长什么样,就越能精准识别异常请求。安全团队应该定期与开发团队、DBA一起复盘数据库访问日志,把新的业务模式纳入基线,把过时的规则下线,让风控系统始终贴合实际运行状态。
