我最近在调一个AI Agent的数据访问项目,Agent已经能通过自然语言自动生成SQL,业务部门提个“上周华东区订单量”就能直接取数。功能倒是跑通了,但上线前我做了件事:把Agent的数据库账号权限全部清空,然后看它到底能读到什么。结果很有意思——别说业务数据,它连表名都拿不到,所有查询全部被拦截。这个实测让我想清楚了一件事:在权限管控缺失的情况下,AI Agent和普通用户一样,访问不到任何数据;而权限管控做到位之后,Agent确实变得“可控”了。这篇文章围绕某数据库安全管控平台(以下统称某平台)的实测展开,核心就一个问题:没有权限,AI Agent是不是真的读不到数据。我会拆解它的权限模型、实测过程、绕过尝试,以及落地AI Agent数据访问时要注意的工程细节。如果你正在做Agent+数据库查询、数据安全治理或者RAG查询增强,这篇应该能给你一些可以直接参考的结论。1. 为什么AI Agent读数据比普通应用更需要“无权限即不可见”很多人觉得AI Agent就是一个“高级查询工具”,给它一个数据库账号,让它能查就行。但我实测后发现,Agent访问数据的风险敞口比普通应用大得多,权限控制必须前置到数据库侧,而不是指望Agent“自觉”。1.1 Agent的行为特征放大了数据安全风险普通业务应用执行的SQL基本是写死的,比如订单列表页就是SELECT ... FROM orders WHERE user_id = ?,参数是用户传进来的,但语句结构可控。AI Agent完全不是这个模式。它基于大模型做推理,会把自然语言拆成多步任务,自己决定查哪张表、关联哪个字段、要不要聚合。这就带来三个风险。第一,Agent会“试探”。遇到查询失败,它可能换一种写法重试,比如先查表结构、再查数据字典,甚至尝试读取系统表。如果权限给得宽,这些试探就可能变成数据泄露。第二,大模型存在幻觉,可能生成语法正确但逻辑错误的SQL,比如把两张不相干的表关联起来,或者查出一个超大结果集。权限管控至少能把查询范围限制在允许的集合内。第三,Agent往往会并发执行多个子任务,连接池占用和短时大量查询会放大风险,一旦账号权限过大,影响面就不是一条SQL,而是一批SQL。一开始我以为,只要在应用代码里做个SQL白名单过滤就行。后来发现这个思路有漏洞。Agent生成的SQL是动态的,没法穷举白名单;关键词黑名单也不可靠,绕过方式太多了。更关键的是,应用层过滤只能挡“应用自己发出的请求”,如果Agent因为提示词注入被诱导,或者底层连接被滥用,过滤就形同虚设。1.2 常见做法为什么不够很多团队现在的做法是:给Agent创建一个只读账号,然后把所有业务表的SELECT权限一授了事。这个方案看着简单,实际漏洞不少。只读账号不等于最小权限。一张订单表里可能有客户手机号、身份证、支付信息,Agent可能只是需要订单金额和地区,但因为整表可读,敏感列一样能被查走。行级权限也没法控制,如果Agent服务于多个租户,理论上它应该只能看到当前租户的数据,但一个只读账号能看到全表。还有,只读账号同样能读information_schema,Agent可以通过元数据探测摸清整个库的表结构,为后续攻击提供信息。所以说,普通只读账号解决的是“能不能写”的问题,解决不了“能看什么”的问题。1.3 数据库安全管控平台的定位某平台这类产品做的事情,是把账号管理、权限审批、数据脱敏、审计日志统一收敛到数据库前面的一层控制面上。Agent不再直连数据库,而是连到平台提供的代理地址,平台根据Agent的账号身份映射到真实数据库账号,再执行权限策略。这个架构最大的特点是把“权限”从数据库账号本身剥离出来,变成一个独立可管可控的策略层。DBA不用再为每个Agent创建复杂的数据库账号,也不用在数据库里反复调试授权语句,只要在平台上定义角色、配置策略、绑定数据源,剩下的由平台执行。我选择用它做实测,原因主要有三个:一是想验证“无权限即不可见”是不是真的能拦死;二是看行级、列级、脱敏这些策略对Agent生成的动态SQL有没有效果;三是看绕过尝试能走到哪一步。下面我把实测过程完整拆开讲。2. 权限模型拆解:从账号分配到动态脱敏某平台的权限模型并不复杂,核心是几个元素的组合:用户、角色、数据源、库表、敏感列、行级策略、脱敏策略。但它的执行逻辑值得细看,尤其是“先拒绝,后放行”这套默认策略。2.1 先拒绝、后放行的默认策略我给Agent创建账号的时候,系统会要求先配置权限策略再激活,默认状态下新账号没有任何可访问的数据源。也就是说,空账号连数据库连接都建立不了,或者说建立连接后,执行任何语句都会返回权限不足。这个设计思路我叫它“白名单思维”:第一条规则是拒绝所有访问,然后由管理员显式添加允许访问的库、表、字段。相比之下,传统数据库授权是黑名单思维,默认能看,只是某些对象不允许看。对AI Agent来说,白名单思维优势明显,因为Agent永远不知道边界在哪,让它在白名单范围内探索,最多是查不到,不会越界。平台层面也支持“先拒绝特定操作,再放行指定操作”的精细化配置。比如某个角色只能执行SELECT,那就把INSERT、UPDATE、DELETE、DROP全部拒绝,再放行SELECT。实测中我发现,这种配置模式下,Agent生成的INSERT语句会被直接拦截,错误信息是权限不足,而不会真的写进数据库。2.2 最小权限基线:库、表、视图、字段最小权限是安全控制的老生常谈,但到了Agent场景需要更进一步。我实测时并没有直接授予Agent业务表的SELECT权限,而是先创建了一个仅含必要字段的视图,然后只给Agent这个视图的查询权限。具体是这么做的:订单表orders里有order_id、customer_id、region、amount、pay_status、customer_phone等多个字段,Agent实际只需要分析订单金额和地区分布,不涉及电话号码。于是我在数据库中创建一个视图v_order_analysis,只包含order_id、region、amount、order_date四个字段,然后把视图的SELECT权限授给Agent账号。这样做的好处有两个。第一,敏感字段在视图层就被剥离开了,Agent查不到自然就不会生成相关SQL,也减少了敏感信息进入大模型上下文的风险。第二,视图可以在不改变底层表结构的情况下调整暴露字段,DBA维护起来更灵活。我强烈建议任何Agent取数场景都优先走视图,而不是直接授表权限。2.3 行级策略与动态脱敏的配合列级权限解决的是“哪些列能看”,行级策略解决的是“哪些行能看”。某平台支持在策略中配置行级过滤条件,比如Agent属于“华东区”业务线,那么查询订单表时自动追加WHERE region = '华东区'。实测中我发现,行级策略对Agent生成的SQL是有强制作用的。Agent可能生成SELECT region, COUNT(*) FROM orders GROUP BY region,希望统计所有区域的数据。但因为行级策略的存在,实际执行的SQL会被改写为只返回华东区的数据,其他区域的行根本不会出现在结果集里。Agent自身并不知道自己被限制了,它看到的结果就是“系统里只有华东区的订单”,这种效果对防范数据越权非常有效。脱敏策略同样重要。用户表users里的phone字段配置了动态脱敏规则,保留前3位和后4位,中间用星号代替。Agent执行SELECT phone FROM users LIMIT 5返回的是138****5678而不是完整号码。这个脱敏发生在数据返回链路中,底层表数据没有改变,但Agent拿到的是脱敏后的值。如果Agent进一步拿这个手机号去调用外部接口做匹配,拿到的是脱敏值,也就无法还原真实号码。2.4 控制链路:Agent如何连接到数据源某平台的接入方式是以代理模式提供的,Agent应用配置的数据源地址不是数据库实例地址,而是平台提供的代理地址。连接时,Agent使用平台分配的账号和密钥,平台校验身份后,根据账号绑定的角色策略建立到真实数据库的连接。控制链路大致是:Agent应用 -> 平台代理 -> 权限策略引擎 -> 真实数据库。策略引擎会解析Agent发来的SQL,判断涉及哪些库、表、列,再对照当前账号的权限集合做检查。只要有一个对象不在授权范围内,整条语句就会被拒绝,而不是部分执行。这种“整条拒绝”的设计很重要,如果平台只对越权列返回空值而放行其他列,Agent可能会在误差中把空值当成真实数据,干扰后续判断。实测中还发现,平台对SQL的解析能力比我想象的强,它不仅支持MySQL语法,对常见的JOIN、子查询、窗口函数也能识别对象级依赖并做权限检查。比如Agent写一条子查询同时涉及订单表和用户表,即使订单表有权限,用户表没有权限,整条语句也会被拦截,不会出现“半执行”的状态。3. 实测:零权限Agent能读到什么、不能读到什么前面讲了权限模型,这部分是完整的实测记录。我会从环境搭建开始,把每一步的操作、返回结果、观察结论都列出来,方便你复现和对照。3.1 环境与账号创建我准备了一套模拟业务库,用了三个表:orders订单表、users用户表、products产品表。orders里有6000行测试数据,包含客户ID、地区、金额、支付状态、订单日期等字段;users里有用户手机号、身份证号等敏感信息;products是普通产品维表。Agent侧用一个基于Python的查询编排脚本模拟,它会接收自然语言指令,通过模型生成SQL,再通过统一的数据源连接执行。为了方便观察,我把模型生成的SQL和最终执行结果都打印出来。在某平台创建Agent账号时,我故意把权限配置留空,先不授予任何数据源,然后启用账号。3.2 零权限状态下的第一个查询第一轮测试,我给Agent发了一条指令:统计订单表的总行数。模型生成的SQL是:SELECT COUNT(*) FROM orders;执行之后,Agent返回的不是数字,而是平台抛出的权限异常,大致意思是没有访问数据源或表的权限。Agent尝试换一种写法再查,比如直接查SELECT * FROM orders,结果还是被拦截。我又试了更基础的操作,比如:SHOW TABLES;结果同样返回权限不足。这说明平台的拦截是发生在元数据层面的,Agent不仅看不到数据,连表清单都拿不到。“没有权限,AI Agent也读不到数据”在零权限状态下是最彻底的。这个阶段的结论很直接:一个空权限账号对Agent来说基本等于“数据库不存在”。Agent不会因为查询失败就认为自己没权限,它通常会向用户报告“查询遇到异常”,这对业务方来说其实是可接受的,因为没有数据流出。3.3 授权后的行为变化第二轮测试,我在平台上给Agent账号添加了一个只读角色,允许访问视图v_order_analysis,并确认脱敏策略已配置到users.phone字段。未授权前,Agent执行:SELECT order_id, region, amount, order_date FROM v_order_analysis LIMIT 3;返回正常数据。然后我让Agent查询原始订单表的敏感字段,它生成了:SELECT customer_phone FROM orders LIMIT 3;平台直接拦截。此时Agent有点“困惑”,它尝试在v_order_analysis中找customer_phone字段,但视图里根本没有这个字段,所以查询失败。最终Agent告诉用户:无法获取手机号数据,建议联系管理员开通权限。这里有个很有意思的细节:Agent并不会主动说“我没有权限”,它更多是表达“查不到”。但从安全角度看,这个效果完全够用——敏感数据既没有进入Agent的上下文,也没有进入大模型的推理过程。我继续测试了脱敏效果。允许Agent访问users表的phone字段后,执行:SELECT phone FROM users LIMIT 5;返回的数据格式是138****5678。Agent拿这组数据做后续分析时,所有输出里的手机号都是脱敏值。也就是说,即使Agent“有权限”,它接触到的敏感字段仍然是残缺的。3.4 绕过尝试:从schema探测到注入试探只测正常查询还不够,我还要看Agent在“被逼无奈”时会不会尝试绕过权限。我把一些常见的绕行方式全部模拟了一遍,记录如下。第一招,切换schema。Agent尝试:USE information_schema; SELECT table_name FROM tables;平台拦截,信息返回为空。这个结果在意料之中,因为平台的权限检查针对的是数据源和对象,不是简单的数据库名隔离。第二招,元数据探测。Agent尝试:SELECT column_name FROM information_schema.columns WHERE table_name = 'users';同样失败。这很关键,因为很多数据库应用中,information_schema是默认开放的。某平台把元数据访问也纳入了权限范围,Agent连字段名都探测不到,后续构造攻击语句就无从下手。第三招,利用JOIN和子查询间接获取数据。比如Agent知道v_order_analysis可访问,尝试通过它JOINusers表,获取用户手机号:SELECT u.phone FROM v_order_analysis v JOIN users u ON v.customer_id = u.id;平台在执行前解析出SQL涉及users表且访问了phone列,发现该账号对users表无查询权限,整条语句被拒绝。实测中,平台没有返回部分结果,而是直接报错。第四招,借助函数或表达式规避。比如把手机号拼接到注释字段里:SELECT order_id, CONCAT(phone, '') AS x FROM v_order_analysis v;这种也失败,因为平台解析列依赖时发现引用了phone列,而该列来源是users表,未授权则不可用。第五招,UNION类型注入试探:SELECT order_id, amount FROM v_order_analysis UNION SELECT id, phone FROM users;结果同样被拦截。平台对UNION分支的对象做了独立解析,任一支路越权都会拒绝整条查询。我把五种绕过方式的结果整理如下:绕过方式目标平台行为结果切换schema读取系统表获取表清单拒绝访问失败查询information_schema获取字段结构拒绝访问失败JOIN未授权表通过关联获取敏感列整条SQL拒绝失败表达式拼接敏感列绕过列级过滤解析到列依赖后拒绝失败UNION注入试探合并返回敏感数据分支独立解析后拒绝失败测试到这里,我得出的结论是:只要权限管控配置正确,Agent基于模型生成的SQL基本无法通过临时改写来越权访问。3.5 实测结果汇总结合前面几轮测试,可以归纳出几个明确结论。第一,零权限状态下,Agent连数据库连接后的第一条SELECT都会被拦截,更不用说表结构、元数据、业务数据。第二,最小权限配置后,Agent只能在授权范围内工作,查询未授权字段或未授权表都会失败。第三,动态脱敏在数据返回链路生效,Agent拿到的敏感字段已经是处理后的值。第四,常见绕过方式在这个权限模型下走不通,因为检查发生在SQL解析和对象依赖层面,不是简单的客户端过滤。4. 为什么权限控制必须下沉到数据库层实测结果证明了平台的能力,但我想进一步聊聊设计层面的问题:为什么这类权限控制必须放在数据库层,而不是应用层或者中间件层。这关系到你落地方案时的架构选择。4.1 应用层过滤的天然短板我之前也尝试过在Agent应用里做一层SQL过滤,思路是维护一个允许访问的表清单,然后对生成的SQL做关键字匹配。这个方案短期内有效,但长期看问题非常多。Agent生成的SQL是动态的,同样的业务需求可能对应十几种写法。用正则和黑名单去匹配,很容易误伤正常查询,或者漏掉变体写法。更麻烦的是,应用层过滤只对“这个Agent应用”有效,如果Agent的代码被人改了,或者连接信息被其他程序复用,过滤逻辑就失效了。还有一个容易被忽略的问题:应用层过滤看不到数据库账号的真实行为。DBA去查数据库审计日志时,看到的还是Agent账号在执行的SQL,无法区分这条SQL是应用发的还是攻击者通过应用漏洞发的。权限控制放在数据库层,审计日志就会更干净,每条记录都能对应到明确的权限策略。4.2 数据库层管控带来的工程收益把权限控制放到数据库前面的平台代理层,实际上是引入了一个统一策略执行点。Agent连接平台,平台再连数据库。这样DBA不需要在每个数据库里手工创建几十个专用账号,只需要在平台上配置角色和策略,由平台完成账号映射。对AI Agent这种“不可预测SQL”的工作负载,数据库层管控还有一个额外价值:平台可以做到“执行前解析”。它不是在数据库返回结果后做过滤,而是在执行前就把SQL解析成对象访问清单,再做权限比对。这样能做到整条拒绝,避免“部分数据流出后才发现越权”。从运维角度看,权限审计也更方便。Agent每次查询都会产生一条审计记录,包括执行时间、账号、SQL文本、访问对象、结果状态。出现数据安全问题的时候,可以直接在平台上检索,不需要到数据库日志里翻。4.3 这套方案的边界与代价说了这么多优点,边界和代价也必须说清楚。第一,动态脱敏可能影响统计分析结果。比如Agent对脱敏后的手机号做去重统计,因为中间四位被隐藏,去重数量会比真实值偏大。如果你的Agent是拿这些数据做精确分析,一定要在提示词里说明“部分字段为脱敏值”。第二,行级权限会让Agent对数据分布产生误判。前面提到华东区Agent查订单统计时只看到华东区的数据,它可能会据此得出“系统没有其他区域订单”的结论。这不是平台的缺陷,但需要Agent应用层配合,明确告知模型“数据范围受权限限制”。第三,平台代理会增加一条网络链路,查询时延会有所上升。实测中,本地环境下单次查询增加了约几毫秒到十几毫秒,对多数分析场景可接受,但对高并发低时延OLTP查询可能有影响。第四,复杂SQL的解析能力不是无限的。平台对主流语法支持较好,但遇到超长嵌套、存储过程调用、临时表操作时,解析逻辑可能失效。这类场景下还是应该从源头上限制Agent的SQL生成策略,不让它写出过于复杂的语句。5. AI Agent数据访问落地建议与实际运维细节最后这部分是我的实操经验。权限管控配置好只是第一步,真正上线AI Agent数据访问还需要把流程和管理制度补上,否则权限策略会变成一纸空文。5.1 账号生命周期与最小权限申请我给Agent创建账号时,坚持一套固定流程:业务方提交申请表,明确需要的数据表、字段、数据范围、使用场景;DBA审批后,先在测试环境搭建视图和脱敏策略;测试通过后再到生产环境配置。每个Agent账号只服务一个Agent应用,不共用。账号回收同等重要。Agent版本更新后,旧的查询逻辑可能不再使用某些表,这部分权限要及时回收。我习惯在平台上设定三个月Review一次权限清单,把最近三个月没有访问记录的对象权限移除。这个动作靠人工记忆不现实,平台提供的审计日志正好可以作为依据。5.2 提示词与SQL生成的联动约束权限管控管住了“Agent能执行什么”,但管不住“Agent想尝试什么”。为了减少查询失败和误报,我会在Agent的提示词里加入权限范围说明。比如明确写:“当前可访问的数据源是订单分析视图,包含订单ID、地区、金额、日期。用户手机号等敏感字段不可访问,不要尝试查询。”添加这段话之后,Agent生成的SQL明显“规矩”很多,不再频繁尝试越权查询。还有一个细节:Agent返回权限异常时,不应该直接把异常堆栈告诉用户。实测中我把异常处理改成“我无法访问该数据,请确定查询范围”,用户侧体验会好很多,也避免暴露底层权限结构。5.3 审计日志与异常告警权限管控平台最容易被忽略的价值其实是审计。上线Agent后,我会定期查看审计日志,关注几类异常:短时间内大量失败查询、尝试访问未授权表、执行时间异常的慢SQL。我在某平台上配置了告警规则:一分钟内失败查询超过10次就告警。这个阈值在正常使用情况下不应该触发,一旦触发,说明Agent可能出现了提示词注入,或者权限配置有误。告警信息推给值班群,处理速度远快于事后看日志。审计日志还有一个作用:为权限变更提供依据。业务方说“Agent查不到某个数据”时,我可以直接翻日志,看到底是因为没权限,还是因为SQL本身没写对。这能省去大量沟通成本。5.4 变更流程和定期复核权限配置变更我坚持走“申请、审批、执行、验证”四步。即使是Agent本身提出的需求调整,也要由业务方确认,不能由Agent开发者自己直接改权限。这个流程看似繁琐,但在多人协作时非常管用,能避免某个人误操作导致权限越扩。定期复核方面,除了三到六个月Review权限清单外,我还会在每次Agent大版本更新前做一次权限复查,确认新版本用到的表和字段范围。如果新版本需要新的表或字段,提前走权限申请流程,不要等上线后在生产环境临时加权限。另外,我还养成了一个习惯:上线前把Agent可访问的表全部列出来,对照最小权限表,逐项确认“这张表的哪些字段没有暴露、哪些敏感列已脱敏”。这套核对清单做完,基本可以放心让Agent面向业务使用了。这次实测给我最大的体会是:权限管控不是为了限制AI Agent,而是为了让Agent真正变得可信。没有权限管控,Agent的能力越强,风险越大;有了“无权限即不可见”的底座,后续各种数据应用才能放手推进。最后分享一个小技巧:如果你刚开始做Agent取数,优先用视图而不是直接授表,把敏感字段在视图层剥离开,往往是最省事也最稳妥的起点。
我最近在调一个AI Agent的数据访问项目,Agent已经能通过自然语言自动生成SQL,业务部门提个“上周华东区订单量”就能直接取数。功能倒是跑通了,但上线前我做了件事:把Agent的数据库账号权限全部清空,然后看它到底能读到什么。结果很有意思——别说业务数据,它连表名都拿不到,所有查询全部被拦截。这个实测让我想清楚了一件事:在权限管控缺失的情况下,AI Agent和普通用户一样,访问不到任何数据;而权限管控做到位之后,Agent确实变得“可控”了。这篇文章围绕某数据库安全管控平台(以下统称某平台)的实测展开,核心就一个问题:没有权限,AI Agent是不是真的读不到数据。我会拆解它的权限模型、实测过程、绕过尝试,以及落地AI Agent数据访问时要注意的工程细节。如果你正在做Agent+数据库查询、数据安全治理或者RAG查询增强,这篇应该能给你一些可以直接参考的结论。1. 为什么AI Agent读数据比普通应用更需要“无权限即不可见”很多人觉得AI Agent就是一个“高级查询工具”,给它一个数据库账号,让它能查就行。但我实测后发现,Agent访问数据的风险敞口比普通应用大得多,权限控制必须前置到数据库侧,而不是指望Agent“自觉”。1.1 Agent的行为特征放大了数据安全风险普通业务应用执行的SQL基本是写死的,比如订单列表页就是SELECT ... FROM orders WHERE user_id = ?,参数是用户传进来的,但语句结构可控。AI Agent完全不是这个模式。它基于大模型做推理,会把自然语言拆成多步任务,自己决定查哪张表、关联哪个字段、要不要聚合。这就带来三个风险。第一,Agent会“试探”。遇到查询失败,它可能换一种写法重试,比如先查表结构、再查数据字典,甚至尝试读取系统表。如果权限给得宽,这些试探就可能变成数据泄露。第二,大模型存在幻觉,可能生成语法正确但逻辑错误的SQL,比如把两张不相干的表关联起来,或者查出一个超大结果集。权限管控至少能把查询范围限制在允许的集合内。第三,Agent往往会并发执行多个子任务,连接池占用和短时大量查询会放大风险,一旦账号权限过大,影响面就不是一条SQL,而是一批SQL。一开始我以为,只要在应用代码里做个SQL白名单过滤就行。后来发现这个思路有漏洞。Agent生成的SQL是动态的,没法穷举白名单;关键词黑名单也不可靠,绕过方式太多了。更关键的是,应用层过滤只能挡“应用自己发出的请求”,如果Agent因为提示词注入被诱导,或者底层连接被滥用,过滤就形同虚设。1.2 常见做法为什么不够很多团队现在的做法是:给Agent创建一个只读账号,然后把所有业务表的SELECT权限一授了事。这个方案看着简单,实际漏洞不少。只读账号不等于最小权限。一张订单表里可能有客户手机号、身份证、支付信息,Agent可能只是需要订单金额和地区,但因为整表可读,敏感列一样能被查走。行级权限也没法控制,如果Agent服务于多个租户,理论上它应该只能看到当前租户的数据,但一个只读账号能看到全表。还有,只读账号同样能读information_schema,Agent可以通过元数据探测摸清整个库的表结构,为后续攻击提供信息。所以说,普通只读账号解决的是“能不能写”的问题,解决不了“能看什么”的问题。1.3 数据库安全管控平台的定位某平台这类产品做的事情,是把账号管理、权限审批、数据脱敏、审计日志统一收敛到数据库前面的一层控制面上。Agent不再直连数据库,而是连到平台提供的代理地址,平台根据Agent的账号身份映射到真实数据库账号,再执行权限策略。这个架构最大的特点是把“权限”从数据库账号本身剥离出来,变成一个独立可管可控的策略层。DBA不用再为每个Agent创建复杂的数据库账号,也不用在数据库里反复调试授权语句,只要在平台上定义角色、配置策略、绑定数据源,剩下的由平台执行。我选择用它做实测,原因主要有三个:一是想验证“无权限即不可见”是不是真的能拦死;二是看行级、列级、脱敏这些策略对Agent生成的动态SQL有没有效果;三是看绕过尝试能走到哪一步。下面我把实测过程完整拆开讲。2. 权限模型拆解:从账号分配到动态脱敏某平台的权限模型并不复杂,核心是几个元素的组合:用户、角色、数据源、库表、敏感列、行级策略、脱敏策略。但它的执行逻辑值得细看,尤其是“先拒绝,后放行”这套默认策略。2.1 先拒绝、后放行的默认策略我给Agent创建账号的时候,系统会要求先配置权限策略再激活,默认状态下新账号没有任何可访问的数据源。也就是说,空账号连数据库连接都建立不了,或者说建立连接后,执行任何语句都会返回权限不足。这个设计思路我叫它“白名单思维”:第一条规则是拒绝所有访问,然后由管理员显式添加允许访问的库、表、字段。相比之下,传统数据库授权是黑名单思维,默认能看,只是某些对象不允许看。对AI Agent来说,白名单思维优势明显,因为Agent永远不知道边界在哪,让它在白名单范围内探索,最多是查不到,不会越界。平台层面也支持“先拒绝特定操作,再放行指定操作”的精细化配置。比如某个角色只能执行SELECT,那就把INSERT、UPDATE、DELETE、DROP全部拒绝,再放行SELECT。实测中我发现,这种配置模式下,Agent生成的INSERT语句会被直接拦截,错误信息是权限不足,而不会真的写进数据库。2.2 最小权限基线:库、表、视图、字段最小权限是安全控制的老生常谈,但到了Agent场景需要更进一步。我实测时并没有直接授予Agent业务表的SELECT权限,而是先创建了一个仅含必要字段的视图,然后只给Agent这个视图的查询权限。具体是这么做的:订单表orders里有order_id、customer_id、region、amount、pay_status、customer_phone等多个字段,Agent实际只需要分析订单金额和地区分布,不涉及电话号码。于是我在数据库中创建一个视图v_order_analysis,只包含order_id、region、amount、order_date四个字段,然后把视图的SELECT权限授给Agent账号。这样做的好处有两个。第一,敏感字段在视图层就被剥离开了,Agent查不到自然就不会生成相关SQL,也减少了敏感信息进入大模型上下文的风险。第二,视图可以在不改变底层表结构的情况下调整暴露字段,DBA维护起来更灵活。我强烈建议任何Agent取数场景都优先走视图,而不是直接授表权限。2.3 行级策略与动态脱敏的配合列级权限解决的是“哪些列能看”,行级策略解决的是“哪些行能看”。某平台支持在策略中配置行级过滤条件,比如Agent属于“华东区”业务线,那么查询订单表时自动追加WHERE region = '华东区'。实测中我发现,行级策略对Agent生成的SQL是有强制作用的。Agent可能生成SELECT region, COUNT(*) FROM orders GROUP BY region,希望统计所有区域的数据。但因为行级策略的存在,实际执行的SQL会被改写为只返回华东区的数据,其他区域的行根本不会出现在结果集里。Agent自身并不知道自己被限制了,它看到的结果就是“系统里只有华东区的订单”,这种效果对防范数据越权非常有效。脱敏策略同样重要。用户表users里的phone字段配置了动态脱敏规则,保留前3位和后4位,中间用星号代替。Agent执行SELECT phone FROM users LIMIT 5返回的是138****5678而不是完整号码。这个脱敏发生在数据返回链路中,底层表数据没有改变,但Agent拿到的是脱敏后的值。如果Agent进一步拿这个手机号去调用外部接口做匹配,拿到的是脱敏值,也就无法还原真实号码。2.4 控制链路:Agent如何连接到数据源某平台的接入方式是以代理模式提供的,Agent应用配置的数据源地址不是数据库实例地址,而是平台提供的代理地址。连接时,Agent使用平台分配的账号和密钥,平台校验身份后,根据账号绑定的角色策略建立到真实数据库的连接。控制链路大致是:Agent应用 -> 平台代理 -> 权限策略引擎 -> 真实数据库。策略引擎会解析Agent发来的SQL,判断涉及哪些库、表、列,再对照当前账号的权限集合做检查。只要有一个对象不在授权范围内,整条语句就会被拒绝,而不是部分执行。这种“整条拒绝”的设计很重要,如果平台只对越权列返回空值而放行其他列,Agent可能会在误差中把空值当成真实数据,干扰后续判断。实测中还发现,平台对SQL的解析能力比我想象的强,它不仅支持MySQL语法,对常见的JOIN、子查询、窗口函数也能识别对象级依赖并做权限检查。比如Agent写一条子查询同时涉及订单表和用户表,即使订单表有权限,用户表没有权限,整条语句也会被拦截,不会出现“半执行”的状态。3. 实测:零权限Agent能读到什么、不能读到什么前面讲了权限模型,这部分是完整的实测记录。我会从环境搭建开始,把每一步的操作、返回结果、观察结论都列出来,方便你复现和对照。3.1 环境与账号创建我准备了一套模拟业务库,用了三个表:orders订单表、users用户表、products产品表。orders里有6000行测试数据,包含客户ID、地区、金额、支付状态、订单日期等字段;users里有用户手机号、身份证号等敏感信息;products是普通产品维表。Agent侧用一个基于Python的查询编排脚本模拟,它会接收自然语言指令,通过模型生成SQL,再通过统一的数据源连接执行。为了方便观察,我把模型生成的SQL和最终执行结果都打印出来。在某平台创建Agent账号时,我故意把权限配置留空,先不授予任何数据源,然后启用账号。3.2 零权限状态下的第一个查询第一轮测试,我给Agent发了一条指令:统计订单表的总行数。模型生成的SQL是:SELECT COUNT(*) FROM orders;执行之后,Agent返回的不是数字,而是平台抛出的权限异常,大致意思是没有访问数据源或表的权限。Agent尝试换一种写法再查,比如直接查SELECT * FROM orders,结果还是被拦截。我又试了更基础的操作,比如:SHOW TABLES;结果同样返回权限不足。这说明平台的拦截是发生在元数据层面的,Agent不仅看不到数据,连表清单都拿不到。“没有权限,AI Agent也读不到数据”在零权限状态下是最彻底的。这个阶段的结论很直接:一个空权限账号对Agent来说基本等于“数据库不存在”。Agent不会因为查询失败就认为自己没权限,它通常会向用户报告“查询遇到异常”,这对业务方来说其实是可接受的,因为没有数据流出。3.3 授权后的行为变化第二轮测试,我在平台上给Agent账号添加了一个只读角色,允许访问视图v_order_analysis,并确认脱敏策略已配置到users.phone字段。未授权前,Agent执行:SELECT order_id, region, amount, order_date FROM v_order_analysis LIMIT 3;返回正常数据。然后我让Agent查询原始订单表的敏感字段,它生成了:SELECT customer_phone FROM orders LIMIT 3;平台直接拦截。此时Agent有点“困惑”,它尝试在v_order_analysis中找customer_phone字段,但视图里根本没有这个字段,所以查询失败。最终Agent告诉用户:无法获取手机号数据,建议联系管理员开通权限。这里有个很有意思的细节:Agent并不会主动说“我没有权限”,它更多是表达“查不到”。但从安全角度看,这个效果完全够用——敏感数据既没有进入Agent的上下文,也没有进入大模型的推理过程。我继续测试了脱敏效果。允许Agent访问users表的phone字段后,执行:SELECT phone FROM users LIMIT 5;返回的数据格式是138****5678。Agent拿这组数据做后续分析时,所有输出里的手机号都是脱敏值。也就是说,即使Agent“有权限”,它接触到的敏感字段仍然是残缺的。3.4 绕过尝试:从schema探测到注入试探只测正常查询还不够,我还要看Agent在“被逼无奈”时会不会尝试绕过权限。我把一些常见的绕行方式全部模拟了一遍,记录如下。第一招,切换schema。Agent尝试:USE information_schema; SELECT table_name FROM tables;平台拦截,信息返回为空。这个结果在意料之中,因为平台的权限检查针对的是数据源和对象,不是简单的数据库名隔离。第二招,元数据探测。Agent尝试:SELECT column_name FROM information_schema.columns WHERE table_name = 'users';同样失败。这很关键,因为很多数据库应用中,information_schema是默认开放的。某平台把元数据访问也纳入了权限范围,Agent连字段名都探测不到,后续构造攻击语句就无从下手。第三招,利用JOIN和子查询间接获取数据。比如Agent知道v_order_analysis可访问,尝试通过它JOINusers表,获取用户手机号:SELECT u.phone FROM v_order_analysis v JOIN users u ON v.customer_id = u.id;平台在执行前解析出SQL涉及users表且访问了phone列,发现该账号对users表无查询权限,整条语句被拒绝。实测中,平台没有返回部分结果,而是直接报错。第四招,借助函数或表达式规避。比如把手机号拼接到注释字段里:SELECT order_id, CONCAT(phone, '') AS x FROM v_order_analysis v;这种也失败,因为平台解析列依赖时发现引用了phone列,而该列来源是users表,未授权则不可用。第五招,UNION类型注入试探:SELECT order_id, amount FROM v_order_analysis UNION SELECT id, phone FROM users;结果同样被拦截。平台对UNION分支的对象做了独立解析,任一支路越权都会拒绝整条查询。我把五种绕过方式的结果整理如下:绕过方式目标平台行为结果切换schema读取系统表获取表清单拒绝访问失败查询information_schema获取字段结构拒绝访问失败JOIN未授权表通过关联获取敏感列整条SQL拒绝失败表达式拼接敏感列绕过列级过滤解析到列依赖后拒绝失败UNION注入试探合并返回敏感数据分支独立解析后拒绝失败测试到这里,我得出的结论是:只要权限管控配置正确,Agent基于模型生成的SQL基本无法通过临时改写来越权访问。3.5 实测结果汇总结合前面几轮测试,可以归纳出几个明确结论。第一,零权限状态下,Agent连数据库连接后的第一条SELECT都会被拦截,更不用说表结构、元数据、业务数据。第二,最小权限配置后,Agent只能在授权范围内工作,查询未授权字段或未授权表都会失败。第三,动态脱敏在数据返回链路生效,Agent拿到的敏感字段已经是处理后的值。第四,常见绕过方式在这个权限模型下走不通,因为检查发生在SQL解析和对象依赖层面,不是简单的客户端过滤。4. 为什么权限控制必须下沉到数据库层实测结果证明了平台的能力,但我想进一步聊聊设计层面的问题:为什么这类权限控制必须放在数据库层,而不是应用层或者中间件层。这关系到你落地方案时的架构选择。4.1 应用层过滤的天然短板我之前也尝试过在Agent应用里做一层SQL过滤,思路是维护一个允许访问的表清单,然后对生成的SQL做关键字匹配。这个方案短期内有效,但长期看问题非常多。Agent生成的SQL是动态的,同样的业务需求可能对应十几种写法。用正则和黑名单去匹配,很容易误伤正常查询,或者漏掉变体写法。更麻烦的是,应用层过滤只对“这个Agent应用”有效,如果Agent的代码被人改了,或者连接信息被其他程序复用,过滤逻辑就失效了。还有一个容易被忽略的问题:应用层过滤看不到数据库账号的真实行为。DBA去查数据库审计日志时,看到的还是Agent账号在执行的SQL,无法区分这条SQL是应用发的还是攻击者通过应用漏洞发的。权限控制放在数据库层,审计日志就会更干净,每条记录都能对应到明确的权限策略。4.2 数据库层管控带来的工程收益把权限控制放到数据库前面的平台代理层,实际上是引入了一个统一策略执行点。Agent连接平台,平台再连数据库。这样DBA不需要在每个数据库里手工创建几十个专用账号,只需要在平台上配置角色和策略,由平台完成账号映射。对AI Agent这种“不可预测SQL”的工作负载,数据库层管控还有一个额外价值:平台可以做到“执行前解析”。它不是在数据库返回结果后做过滤,而是在执行前就把SQL解析成对象访问清单,再做权限比对。这样能做到整条拒绝,避免“部分数据流出后才发现越权”。从运维角度看,权限审计也更方便。Agent每次查询都会产生一条审计记录,包括执行时间、账号、SQL文本、访问对象、结果状态。出现数据安全问题的时候,可以直接在平台上检索,不需要到数据库日志里翻。4.3 这套方案的边界与代价说了这么多优点,边界和代价也必须说清楚。第一,动态脱敏可能影响统计分析结果。比如Agent对脱敏后的手机号做去重统计,因为中间四位被隐藏,去重数量会比真实值偏大。如果你的Agent是拿这些数据做精确分析,一定要在提示词里说明“部分字段为脱敏值”。第二,行级权限会让Agent对数据分布产生误判。前面提到华东区Agent查订单统计时只看到华东区的数据,它可能会据此得出“系统没有其他区域订单”的结论。这不是平台的缺陷,但需要Agent应用层配合,明确告知模型“数据范围受权限限制”。第三,平台代理会增加一条网络链路,查询时延会有所上升。实测中,本地环境下单次查询增加了约几毫秒到十几毫秒,对多数分析场景可接受,但对高并发低时延OLTP查询可能有影响。第四,复杂SQL的解析能力不是无限的。平台对主流语法支持较好,但遇到超长嵌套、存储过程调用、临时表操作时,解析逻辑可能失效。这类场景下还是应该从源头上限制Agent的SQL生成策略,不让它写出过于复杂的语句。5. AI Agent数据访问落地建议与实际运维细节最后这部分是我的实操经验。权限管控配置好只是第一步,真正上线AI Agent数据访问还需要把流程和管理制度补上,否则权限策略会变成一纸空文。5.1 账号生命周期与最小权限申请我给Agent创建账号时,坚持一套固定流程:业务方提交申请表,明确需要的数据表、字段、数据范围、使用场景;DBA审批后,先在测试环境搭建视图和脱敏策略;测试通过后再到生产环境配置。每个Agent账号只服务一个Agent应用,不共用。账号回收同等重要。Agent版本更新后,旧的查询逻辑可能不再使用某些表,这部分权限要及时回收。我习惯在平台上设定三个月Review一次权限清单,把最近三个月没有访问记录的对象权限移除。这个动作靠人工记忆不现实,平台提供的审计日志正好可以作为依据。5.2 提示词与SQL生成的联动约束权限管控管住了“Agent能执行什么”,但管不住“Agent想尝试什么”。为了减少查询失败和误报,我会在Agent的提示词里加入权限范围说明。比如明确写:“当前可访问的数据源是订单分析视图,包含订单ID、地区、金额、日期。用户手机号等敏感字段不可访问,不要尝试查询。”添加这段话之后,Agent生成的SQL明显“规矩”很多,不再频繁尝试越权查询。还有一个细节:Agent返回权限异常时,不应该直接把异常堆栈告诉用户。实测中我把异常处理改成“我无法访问该数据,请确定查询范围”,用户侧体验会好很多,也避免暴露底层权限结构。5.3 审计日志与异常告警权限管控平台最容易被忽略的价值其实是审计。上线Agent后,我会定期查看审计日志,关注几类异常:短时间内大量失败查询、尝试访问未授权表、执行时间异常的慢SQL。我在某平台上配置了告警规则:一分钟内失败查询超过10次就告警。这个阈值在正常使用情况下不应该触发,一旦触发,说明Agent可能出现了提示词注入,或者权限配置有误。告警信息推给值班群,处理速度远快于事后看日志。审计日志还有一个作用:为权限变更提供依据。业务方说“Agent查不到某个数据”时,我可以直接翻日志,看到底是因为没权限,还是因为SQL本身没写对。这能省去大量沟通成本。5.4 变更流程和定期复核权限配置变更我坚持走“申请、审批、执行、验证”四步。即使是Agent本身提出的需求调整,也要由业务方确认,不能由Agent开发者自己直接改权限。这个流程看似繁琐,但在多人协作时非常管用,能避免某个人误操作导致权限越扩。定期复核方面,除了三到六个月Review权限清单外,我还会在每次Agent大版本更新前做一次权限复查,确认新版本用到的表和字段范围。如果新版本需要新的表或字段,提前走权限申请流程,不要等上线后在生产环境临时加权限。另外,我还养成了一个习惯:上线前把Agent可访问的表全部列出来,对照最小权限表,逐项确认“这张表的哪些字段没有暴露、哪些敏感列已脱敏”。这套核对清单做完,基本可以放心让Agent面向业务使用了。这次实测给我最大的体会是:权限管控不是为了限制AI Agent,而是为了让Agent真正变得可信。没有权限管控,Agent的能力越强,风险越大;有了“无权限即不可见”的底座,后续各种数据应用才能放手推进。最后分享一个小技巧:如果你刚开始做Agent取数,优先用视图而不是直接授表,把敏感字段在视图层剥离开,往往是最省事也最稳妥的起点。