sql server存储过程默认以execute as caller运行,需显式设置execute as owner或指定用户才能实现权限隔离;所有权链生效前提是所有对象属同一owner,否则跨schema访问会中断权限链。

不写WITH EXECUTE AS就等于没设权限
SQL Server存储过程默认以EXECUTE AS CALLER模式运行——也就是说,谁执行它,里头所有语句(包括SELECT * FROM sys.tables)就用谁的权限去查。这不是隔离,是裸奔。常见报错The SELECT permission was denied on the object 'sys.tables',往往就是用户没被授元数据权限,又没关掉CALLER模式。
EXECUTE AS OWNER是最安全的起点
它让过程始终以创建者(通常是dbo)身份执行,调用者只需EXECUTE权限,无需底层表的SELECT/INSERT等权限。所有权链能生效的前提是:过程里访问的所有对象(表、视图、其他过程)都属同一个owner(比如全是dbo)。否则权限检查会在跨schema时中断,比如sales.Customers访问hr.Employees就会失败。
- 声明方式:
CREATE PROCEDURE dbo.GetActiveOrders WITH EXECUTE AS OWNER AS ... - 别用
EXECUTE AS SELF:它把创建时的login名硬编码进定义,DBA换人后容易因owner变更导致执行失败 -
EXECUTE AS OWNER不等于“给owner账号开后门”——只要dbo本身不被普通用户直接登录或滥用,就是可控的
EXECUTE AS 'username'适合最小权限场景
当你需要过程严格受限(比如只允许UPDATE某几个字段),就该用专用执行账户,如proc_executor。这个账户必须已存在,且数据库中已有对应USER(不能只是server-level login)。
- 声明方式:
CREATE PROCEDURE dbo.UpdateOrderStatus WITH EXECUTE AS 'proc_executor' AS ... - 该账户只被授予过程内部涉及的极少数表的最小必要权限,且禁止交互式登录
- 注意调用链:如果过程里又
EXEC了另一个没设EXECUTE AS的过程,权限会回落到caller,可能意外突破边界
动态SQL和跨schema访问必须特别小心
EXEC(@sql)在CALLER模式下完全继承调用者权限,极易被注入利用;换成OWNER或指定用户后,动态SQL的执行范围才被框定。跨schema访问(如sales.Customers)会立即中断所有权链,除非两个schema的owner一致,或显式用EXECUTE AS覆盖上下文。
最常被忽略的一点:权限不是写在过程里就自动生效的——它依赖所有权链的完整性、执行账户的存在性、以及调用链中每个环节是否都做了上下文约束。漏掉任意一环,隔离就形同虚设。











