真正最小化权限需控制“过程能干什么”:只授EXECUTE权限,禁用表权限;用EXECUTE AS 'proc_executor'锁定执行身份,显式授予过程所需最小权限,并确保跨库引用完整三段名且目标库授权到位。

直接给用户 EXECUTE 权限是必要但远远不够的——真正最小化权限,得控制“过程能干什么”,而不是“谁能让它跑起来”。
只授 EXECUTE,别给表权限
用户只需要运行过程,就只该有 EXECUTE 权限,绝不能顺手配上 SELECT 或 UPDATE 表权限。否则等于开了后门:GRANT EXECUTE ON dbo.usp_GetOrder TO app_user 就够了,别跟一句 GRANT SELECT ON dbo.Orders TO app_user。
常见错误现象:
- 用户用
EXEC usp_GetOrder能查订单,但也能直接SELECT * FROM Orders——说明表权限没清理干净 - 审计时发现
app_user在日志里频繁访问sys.tables——大概率是过程里用了SELECT *且调用者本身有元数据权限
用 EXECUTE AS 'proc_executor' 锁死执行身份
不加 EXECUTE AS,过程默认以调用者身份查表,权限随用户走;加了 EXECUTE AS OWNER 又太危险——owner 往往是 dbo,等于把 db_owner 权限借出去。
正确做法是显式指定一个低权限专用账户:
- 先建账号:
CREATE USER proc_executor WITHOUT LOGIN - 只授过程内真正需要的权限,比如仅
SELECT某张日志表:GRANT SELECT ON dbo.RequestLog TO proc_executor - 创建过程时绑定:
CREATE PROCEDURE usp_LogRequest WITH EXECUTE AS 'proc_executor' AS ...
这样无论谁调用,过程都只用 proc_executor 的权限干活,调用者连 SELECT 这张表的权限都不用有。
避免跨库/跨 schema 权限断裂
过程如果引用其他数据库的表(比如 OtherDB.dbo.Config),光在本库授 EXECUTE 不管用——SQL Server 会检查调用链上每一步的权限。
必须显式授权:
- 目标库要开
TRUSTWORTHY OFF(默认就是关的,别动) - 在
OtherDB中给proc_executor授SELECT:USE OtherDB; GRANT SELECT ON dbo.Config TO proc_executor - 对象引用必须带完整三段名:
OtherDB.dbo.Config,不能只写dbo.Config
漏掉任何一环,过程一执行就报错:The server principal "proc_executor" is not able to access the database "OtherDB" under the current security context.
别信 db_executor 角色
SQL Server 自带的 db_executor 角色并不存在——这是常见误解。有人试过 sp_addrolemember 'db_executor', 'user',结果报错:Cannot find the role 'db_executor'...。
真正可用的是:
-
db_executor是假的,别用 - 想批量授所有过程的
EXECUTE,用架构级授权:GRANT EXECUTE ON SCHEMA :: dbo TO app_user - 想限制只能执行特定几个过程,就得逐个
GRANT EXECUTE ON usp_X TO app_user
最易被忽略的一点:权限变更不会立即生效。如果刚授完权就测试失败,先确认是否连到了正确的数据库上下文——USE YourDB 必须在 GRANT 前执行,否则权限可能落在 master 里。

















