适用于:SQL Server
Azure SQL 数据库
Azure SQL 托管实例
本文介绍了 SQL Server 如何使用安全缓存来验证主体有权访问安全对象的权限。
目的
数据库引擎组织实体的分层集合,称为安全对象,可以使用权限进行保护。 最突出的安全对象是服务器和数据库,但也可以更精细地设置权限。 SQL Server 通过确保主体具有适当的权限来控制对安全对象的操作。
下图显示了用户 Alice 在服务器级别具有登录名,以及映射到每个不同数据库中同一登录名的三个不同的用户。
为了优化身份验证过程,SQL Server 使用安全缓存。
无缓存工作流
当安全缓存无效时,SQL Server 将遵循无缓存工作流来验证权限。 本部分介绍无缓存工作流。
若要演示,请考虑以下查询:
SELECT t1.Column1,
t2.Column1
FROM Schema1.Table1 AS t1
INNER JOIN Schema2.Table2 AS t2
ON t1.Column1 = t2.Column2;
当安全缓存无效时,服务在解析查询之前完成以下工作流中所述的步骤。
对于 SQL Server,没有安全缓存的任务包括:
- 连接到实例。
- 执行登录验证。
- 创建安全上下文令牌和登录令牌。 下一部分将介绍这些令牌的详细信息。
- 连接到 数据库。
- 在数据库中创建数据库用户令牌。
- 检查数据库角色的成员身份。 例如,db_datareader、db_datawriter或db_owner。
- 验证用户对所有列的权限,例如,对
t1.Column1
和t2.Column1
列的用户权限。 - 检查所有表的用户权限,例如
table1
和table2
,以及Schema1
和Schema2
上的架构权限。 - 验证数据库权限。
SQL Server 对用户所属的每个角色重复此过程。 获取所有权限后,服务器会执行检查,以确保用户在链中具有所有必要的许可,并且链中没有任何一个拒绝。 权限检查完成后,查询执行将开始。
有关详细信息,请查看 权限检查算法的摘要。
为了简化验证,SQL Server 使用安全缓存。
安全缓存定义
安全缓存存储用户的权限或数据库或服务器中各种安全对象的登录名。 其优点之一是加快查询执行速度。 在 SQL Server 执行查询之前,它会检查用户是否具有不同数据库安全对象的必要权限,例如架构级权限、表级权限和列权限。
安全缓存对象
为了使上一部分中介绍的工作流更快,SQL Server 在安全缓存中缓存许多不同的对象。 缓存的一些对象包括:
令牌 | DESCRIPTION |
---|---|
SecContextToken |
主体的服务器范围安全上下文在此结构中保留。 它包含用户令牌的哈希表,并用作所有其他缓存的起点或基。 包括对登录令牌、用户令牌、审核缓存和 TokenPerm 缓存的引用。 此外,它还充当服务器级别的登录的基本令牌。 |
LoginToken |
类似于安全上下文令牌。 包含服务器级主体的详细信息。 登录令牌包括各种元素,例如 SID、登录 ID、登录类型、登录名、isDisabled 状态和服务器固定角色成员身份。 此外,它还包含服务器级别的特殊角色,例如 sysadmin 和安全管理员。 |
UserToken |
此结构与数据库级主体相关。 它包括用户名、数据库角色、SID、默认语言、默认架构、ID、角色和名称等详细信息。 每个数据库都有一个用户令牌用于登录。 |
TokenPerm |
记录 UserToken 或 SecContextToken 的安全对象的所有权限。 |
TokenAudit |
键是安全对象类和 ID。 该条目是一系列列表,其中包含对象上每个可审核操作的审核 ID。 服务器审核基于权限检查,详细说明特定用户对特定对象执行的每个可审核作。 |
TokenAccessResult |
此缓存存储单个查询的查询权限检查结果,每个查询计划有一个条目。 它是最重要的且最常用的缓存,因为它是在查询执行过程中检查的第一件事。 为了防止临时查询泛滥缓存,仅当执行查询三次时,它才会存储查询权限检查结果。 |
ObjectPerm |
这会记录数据库中针对数据库中所有用户的对象的所有权限。 TokenPerm 和 ObjectPerm 之间的区别在于 TokenPerm 适用于特定用户,而 ObjectPerm 可以为数据库中的所有用户。 |
安全缓存库
令牌存储在不同的缓存存储中。
存储 | DESCRIPTION |
---|---|
TokenAndPermUserStore |
一个大存储区,其中包含以下所有对象: - SecContextToken - LoginToken - UserToken - TokenPerm - TokenAudit |
SecCtxtACRUserStore |
访问检查结果(ACR)存储。 每次登录都有其自己独立的安全上下文的用户存储库。 |
ACRUserStore |
访问验证结果存储<unique id> - <db id> - <user id> 每个用户都有单独的 ACR 用户存储库。 例如,在两个不同数据库中进行的两次登录涉及五个用户,总共相当于产生两个 SecCtxtACRUserStore 和 10 个不同的 ACRUserStore 。 |
ObjectPerm |
每个数据库一个ObjPerm 令牌。 数据库中的所有不同安全对象。 |
已知问题
本部分介绍安全缓存的问题。
安全缓存失效
各种方案可以在数据库或服务器级别触发安全缓存失效。 发生无效作时,所有当前缓存条目都会失效。 所有将来的查询和权限检查都遵循完整的“无缓存”工作流,直到重新填充缓存。 失效可能会显著影响服务器性能,尤其是在高负载下,因为所有活动连接都需要重建缓存条目。 重复的缓存失效可能会使这种影响变得更糟。 数据库中的 master
失效被视为服务器范围的失效,从而影响实例上所有数据库的缓存。
SQL Server 2025 引入了一项仅使特定登录名的缓存失效的功能。 这意味着,当安全缓存条目失效时,只会影响属于受影响登录名的那些条目。 例如,如果向登录 L1 授予新权限,则登录 L2 的令牌将不受影响。
作为初始步骤,此功能适用于 CREATE、ALTER 和 DROP 登录方案,以及单个登录名的权限更改。 群组登录继续遭遇服务器级别的失效。
下表列出了所有会使安全缓存失效的安全数据定义语言(DDL)操作。
行动 | 使用者 | 范围 |
---|---|---|
CREATE/ALTER/DROP |
APPLICATION ROLE SYMMETRIC KEY ASYMMETRIC KEY AUTHORIZATION CERTIFICATE ROLE SCHEMA USER |
指定的数据库 |
DROP |
出现在sys.all_objects或数据库或架构范围内的安全对象列表中列出的任何安全对象。 | 指定的数据库 |
GRANT/DENY/REVOKE |
对数据库或架构包含的安全对象的任何权限。 | 指定的数据库 |
CREATE/ALTER/DROP |
LOGIN ( SERVICE ) MASTER KEY |
SQL Server 实例 |
ALTER |
DATABASE |
指定的数据库 |
当 TokenAndPermUserStore 的大小增长时,查询性能表现
性能问题(如 CPU 使用率高和内存消耗增加)可能是由于 TokenAndPermUserStore 缓存中的条目过多造成的。 默认情况下,SQL Server 仅在检测到内部内存压力时清理此缓存中的条目。 但是,在具有大量 RAM 的服务器上,内部内存压力可能不会频繁发生。 随着缓存的增长,搜索现有条目重复使用所需的时间将增加。 此缓存由旋转锁管理,一次只允许一个线程执行搜索。 因此,此行为可能会导致查询性能和 CPU 使用率降低。
解决方法
SQL Server 提供了两个跟踪标志(TF),可用于为 TokenAndPermUserStore 缓存设置配额。 默认情况下,没有配额,这意味着缓存可以保留无限数量的条目。
- TF 4618:将 TokenAndPermUserStore 中的条目数限制为 1024。
- TF 4618 和 TF 4610:将 TokenAndPermUserStore 中的条目数限制为 8192。 如果 TF 4618 的条目计数限制较低导致其他性能问题,建议同时使用追踪标志 4610 和 4618。 有关详细信息,请参阅 DBCC TRACEON - 跟踪标志(Transact-SQL)。
有关详细信息,可以参考文章 TokenAndPermUserStore 缓存中的过多条目可能导致性能问题 - SQL Server
最佳做法
本部分列出了优化安全工作流的最佳做法。
非尖尖时间的用户管理
鉴于安全缓存(数据库/服务器级别)的高级失效性质,请在服务器负载较低时在非业务时间内执行安全 DDL。 如果在繁重的工作负荷期间发生安全缓存失效,则整个服务器的性能可能会有明显的影响,因为安全缓存会重新填充。
使用单个事务进行权限修改
在同一事务中执行多个安全数据定义语言(DDL)操作可以显著增加与其他活动连接发生死锁的可能性。为了缓解此风险,建议避免在单个事务中执行多个安全 DDL 操作。 为了尽量减少锁争用,应在单独的事务中执行与安全相关的DDL操作。