WITH ENCRYPTION不是真正加密,而是不可逆的源码模糊化,仅防普通用户查看,不防DBA、备份提取或内存分析,且不替代权限控制。

WITH ENCRYPTION是 SQL Server 中唯一原生支持的存储过程源码保护机制,但它不是真正意义上的“加密”,而是一种模糊化(obfuscation)手段,且**不可逆、不防高权限用户、不替代访问控制**。直接使用它前,必须清楚它的边界和风险。
为什么 WITH ENCRYPTION 不能叫“加密”
SQL Server 并未用密钥对存储过程文本做可逆加解密;它只是把原始 CREATE PROCEDURE 语句中的字符序列打乱、替换、移除空格与注释,并转换为二进制 blob 存入系统表 sys.sysobjvalues(SQL Server 2019 及以前)或 sys.sql_modules(仅显示 NULL 值)。这意味着:
- DBA 或 sa 权限用户可通过 DAC 连接 + 内部函数(如
sys.dm_exec_describe_first_result_set配合调试技巧)或第三方工具还原近似源码 - 它不依赖证书、密钥或 TDE,也不受 Always Encrypted 影响
- 一旦创建时加了
WITH ENCRYPTION,后续ALTER PROCEDURE必须显式带上该子句,否则会自动丢失保护(即变回明文)
CREATE PROCEDURE ... WITH ENCRYPTION 的正确写法
注意:必须在 AS 关键字前紧接 WITH ENCRYPTION,中间不能换行或插入注释。
CREATE OR ALTER PROCEDURE dbo.GetCustomerSummary
@Region NVARCHAR(50)
WITH ENCRYPTION
AS
BEGIN
SELECT CustomerID, CompanyName, OrderCount
FROM Customers c
OUTER APPLY (
SELECT COUNT(*) AS OrderCount
FROM Orders o
WHERE o.CustomerID = c.CustomerID
) t
WHERE c.Region = @Region;
END;
常见错误包括:
- 漏写
WITH ENCRYPTION导致ALTER后源码暴露 - 在
CREATE和WITH ENCRYPTION之间加了换行或注释,SQL Server 会静默忽略该子句 - 试图用
sp_helptext查看 —— 返回 “对象注释未找到”,这是预期行为,不代表失败
它和 Always Encrypted、TDE 完全无关
很多人混淆这三者:
-
WITH ENCRYPTION:只作用于存储过程/函数/视图的定义文本,不影响数据、不涉及密钥管理、不提供运行时保护 -
Always Encrypted:保护列中数据值,密钥不出客户端,与存储过程逻辑无关;你无法在加密列上写WHERE Name LIKE '%abc%'(除非启用 secure enclave) -
TDE:加密整个数据库文件(.mdf/.ldf),防磁盘窃取,但 DBA 仍可执行任意查询看到明文结果
换句话说:WITH ENCRYPTION 是“藏源码”,其他两者是“藏数据”。它们可以共存,但目标不同、机制隔离、不能互相替代。
真正需要商业逻辑防护时,该怎么做?
如果你的场景是防止外包人员、初级 DBA 看到核心算法,WITH ENCRYPTION 能起一定作用;但若面对有经验的内部人员或需审计合规(如等保、GDPR),它远远不够。更实际的做法是:
- 把关键计算逻辑下沉到应用层(C#、Java),数据库只做原子 CRUD
- 用 CLR 集成 + 强签名程序集(需
UNSAFE ASSEMBLY权限),比 T-SQL 更难反编译 - 配合行级安全(RLS)和动态数据掩码(DDM),限制谁能看到哪些数据,从源头减少逻辑暴露必要性
- 所有部署脚本走 CI/CD 流水线,禁止开发环境直连生产库,避免人为导出
最易被忽略的一点:WITH ENCRYPTION 不阻止 EXECUTE 权限持有者调用该过程——它只挡查看,不挡使用。所以权限模型设计比模糊化更重要。










