← 数据分析 Agent

只靠 SQL 字符串校验够吗?还需要哪些防线?

高频 困难 SQL 安全校验 · 第 2 / 2 问 更新于 2026/09/29
Text-to-SQLSQL安全纵深防御数据库权限
本题落地项目AI Agent数据分析平台

简化版

不够。字符串校验是应用层的一道防线,正则会漏、写法可以变形,一旦被绕过,后面就没有东西兜底。安全的 Text-to-SQL 要做纵深防御:Prompt 约束(软防线)→ 应用层 SQL 校验(最好基于 SQL 解析器)→ 数据库层的只读账号和最小授权 → 查询超时与行数上限 → 行级、列级权限 → 调用方的身份与数据归属校验 → 全量审计日志。原则是每一层都假设上一层会失守,让任何单点失效都不至于造成写库、越权或拖垮数据库。

详细版

层次防线防什么单独使用的弱点
生成层Prompt 要求只读、只用给定的表模型无意生成写操作挡不住模型出错和提示注入
应用层SQL 校验:只读前缀、单语句、危险关键字、表白名单、行数上限大部分越界写法正则可能漏检,写法可变形
连接层只读账号、只授予业务表 SELECT、关闭多语句写库、改结构、跨库访问挡不住「只读但越权」的查询
资源层查询超时、行数上限、并发限制、只读副本慢查询拖垮主库不管数据该不该看
数据层行级权限、视图、敏感列脱敏看到不该看的行和列配置成本高
身份层登录认证、业务归属校验用别人的身份或记录执行不管 SQL 本身
审计层记录谁在何时执行了什么 SQL、结果多少行事后追溯和告警只能发现,不能阻止

其中最关键、成本最低的一条是:执行 AI 生成 SQL 的数据库账号,只授予必要表的 SELECT 权限。即使所有应用层校验都被绕过,这个账号也执行不了写操作。

完整版教学

一、为什么单靠字符串校验不够

应用层的字符串校验有两个天然弱点:

一、规则会漏
    正则抽表名漏掉逗号连接的多表写法:from biz_order, secret_table
    关键字前后必须有空格才能匹配:换行、括号紧挨着时可能漏检
二、写法能变形
    同一个意思有很多种 SQL 写法,黑名单永远列不全

黑名单式的校验本质上是在猜「坏写法长什么样」,而攻击者和出错的模型总能写出你没猜到的形式。所以字符串校验是必要的,能挡住绝大多数问题,但它不能是唯一的防线。安全设计的思路要从「挡住坏的」转向「只允许好的」,并且在多个层次同时设防。

二、数据库账号:最小授权是最硬的一道防线

执行 AI 生成 SQL 的账号,不应该是应用的主账号,更不能是 root。最小授权的做法:

-- 单独建一个只读账号,只授予分析用到的表
create user 'ai_reader'@'%' identified by '******';
grant select on shop.biz_order      to 'ai_reader'@'%';
grant select on shop.biz_order_item to 'ai_reader'@'%';
grant select on shop.biz_user       to 'ai_reader'@'%';

这样即使校验被绕过,delete、drop 在数据库层就会因为没有权限直接失败;白名单外的表也查不到。还要注意连接参数:MySQL 的 JDBC 连接串里如果开了 allowMultiQueries=true,一次请求可以执行多条语句,执行 AI SQL 的数据源应该关掉它。

记忆钩子:应用层校验是「尽量挡住」,数据库权限是「做不到」。前者会漏,后者不会。

三、资源层:防止一条查询拖垮数据库

即使是合法的只读查询,也可能是灾难:

select * from biz_order o join biz_order_item i on 1 = 1
→ 笛卡尔积,10 万订单 × 50 万明细 = 500 亿行

资源层的防线:

防线做法
查询超时MySQL 用 max_execution_time,PostgreSQL 用 statement_timeout,或在 JDBC 层设置查询超时
行数上限应用层补上或收紧 limit,结果集只取前 N 行
只读副本AI 查询走从库或数仓,不和线上交易抢主库资源
并发限制同一用户同时执行的分析查询数量设上限

超时要设得比页面等待时间短,比如 10 秒,超时的查询直接中止并提示用户缩小范围。

四、数据层:只读也可能越权

只读账号解决了「能不能改」,但没解决「该不该看」。多租户或多部门场景下,同一张订单表里有不同部门的数据:

销售一部的用户问「本月订单数」
模型写:select count(*) from biz_order where ...
没有部门过滤 → 查到了全公司的订单

应对方式:

  • 视图:给每个角色建只包含其数据范围的视图,AI 只能查视图;
  • 行级安全:PostgreSQL 的 RLS 策略按当前用户自动追加过滤条件;
  • 强制条件注入:应用层在执行前给 SQL 追加租户条件(需要基于语法树改写,拼字符串容易出错);
  • 列级脱敏:手机号、身份证号这类敏感列不进白名单,或者只暴露脱敏后的视图列。

五、身份层:谁在执行这条 SQL

Text-to-SQL 通常是「用户提问 → 生成记录 → 用户点执行」。执行接口如果只凭一个记录 ID 就执行,别人改一下 ID 就能执行不属于自己的 SQL、看到别人的查询结果。所以接口要做三层校验:

登录认证   请求带有效的登录凭证
角色校验   管理类接口只允许管理员
归属校验   这条分析记录属于当前用户,或属于当前用户的会话

归属校验在查询、执行、纠错、删除每个接口上都要做,漏一个就是越权入口。

六、审计:出了问题能追溯

每次执行都记录一条审计日志:

谁        用户 ID、角色
何时      请求时间、执行耗时
查什么    数据集、原始问题、模型生成的 SQL、最终执行的 SQL
结果      成功或失败、失败原因、结果行数

审计日志的价值有三个。第一是事后追溯,出了数据泄露能说清楚「这个数据是谁、在什么时候查走的」。第二是发现异常模式,比如某个用户在十分钟内发起了几十次涉及敏感表的查询,可以据此告警或限流。第三是改进校验规则,被拦下的 SQL 本身就是最好的测试用例,定期回看能发现规则的漏洞。注意「最终执行的 SQL」和「模型生成的 SQL」要分开记,追加了 limit 或改写过的 SQL 与原始生成的不同,审计要看真正执行的那一条。

七、把各层串起来看

用户提问
  → [身份层] 登录、角色、会话归属
  → [生成层] Prompt 只注入允许的表,要求只读
  → [应用层] SQL 解析 + 校验 + 行数上限
  → [连接层] 只读账号、关闭多语句
  → [资源层] 超时、只读副本
  → [数据层] 视图 / 行级安全 / 脱敏
  → 执行
  → [审计层] 记录全过程

每一层都假设前一层可能失守。评估一个方案是否足够安全,可以逐层问一句:如果这一层之前的防线全部失效,这一层能挡住什么?

八、常见误区与追问

  • 误区:SQL 校验规则写得足够多就安全了。 黑名单永远列不全,校验只能「尽量挡住」,必须有数据库权限这种「做不到」的硬防线兜底。
  • 误区:只读账号就等于安全。 只读挡住了写操作,但挡不住越权读取其他部门、其他租户的数据,还需要行级权限或视图。
  • 误区:本地开发用 root 执行 AI 生成的 SQL 没关系,上线再换。 权限设计要从一开始就分离,否则上线时很容易漏改;至少执行 AI SQL 的数据源要单独配置。
  • 误区:只读查询不会影响线上。 笛卡尔积、大表全扫描能把数据库拖垮,要有超时、行数上限和只读副本。
  • 误区:接口只要登录了就能执行。 执行接口要校验记录归属,否则改一个 ID 就能执行别人的 SQL。
  • 追问:怎么给 AI 查询做多租户隔离? 用视图或行级安全把租户过滤放到数据库层,或者基于语法树在执行前强制追加租户条件,不要依赖模型自己写过滤条件。
  • 追问:审计日志主要记什么? 用户、时间、数据集、原始问题、生成与最终执行的 SQL、结果行数、耗时和失败原因。

九、加强记忆

字符串校验是必要的应用层防线,但规则会漏、写法会变形,不能单独依赖。纵深防御按层记:生成层 Prompt 约束,应用层 SQL 校验,连接层只读账号与最小授权并关闭多语句,资源层超时、行数上限与只读副本,数据层视图、行级安全与脱敏,身份层登录、角色与归属校验,审计层记录全过程。最硬、成本最低的一条是给执行 AI SQL 的账号只授予业务表的 SELECT 权限:应用层是「尽量挡住」,数据库权限是「做不到」。设计时逐层追问:前面全部失守,这一层还能挡住什么。

项目实战落地

项目里怎么做的

《AI Agent数据分析平台》在应用这一侧设了几道防线:

  • 生成层:SQL 生成模板要求「生成只读 SQL,只返回 JSON」,上下文只包含当前数据集下启用的表和指标;
  • 应用层:执行前的 validateSql 检查只读前缀、剥离字符串后的分号、危险关键字、表白名单,并在没有 limit 时追加 limit 100;
  • 身份层:JWT 登录认证、管理员接口拦截、业务归属校验三层边界——普通用户只能操作自己的会话、分析记录、计划和报告,执行、纠错、图表、解读每个接口都先校验记录归属;
  • 配置层:模型配置接口返回给普通用户时,apiKey 被置为空字符串,真实 Key 只在后端调用模型时使用;
  • 审计层:每条分析记录保存生成的 SQL、最终执行的 safe_sql、安全校验状态与说明、执行耗时、结果条数和错误信息。

这是一个本地运行的学习项目,SQL 执行复用应用本身的数据源,没有单独配置只读账号和查询超时;这两层属于上线时必须补上的数据库层防线,面试时要能说清楚它们应该加在哪里。

为什么这样取舍

  • 防线优先放在业务链路里:身份与归属校验、表白名单、结果留痕都和页面功能绑在一起,学员能从页面操作一路追到后端代码。
  • 记录保存「最终执行的 SQL」而不只是模型生成的 SQL:追加了 limit 之后两者不同,审计时要看真正执行的那一条。

面试官还会追问

  • 管理员接口拦截时,当前用户的角色是从哪里取的?前端把菜单隐藏掉算不算权限控制?
  • 普通用户查分析记录列表时,后端怎么保证只返回自己的数据?管理员查询时有什么不同?

学完《AI Agent数据分析平台》,上面这些追问你都会迎刃而解。

本题落地项目登峰造极AI Agent数据分析平台基于Agent、Text-to-SQL和安全查询执行,实现数据集管理、指标口径维护、分析意图识别、SQL纠错、图表推荐、数据解读和报告生成,适合BI分析落地、过程追踪和多轮会话。SpringbootSpringAIAgentText-to-SQLLLM源码+SQL喂饭学习教程配套面试文档环境安装文档项目运行文档 学习这个项目