深度解析:如何查询 SQL Server 中所有用户的权限与访问状态

在数据库管理与运维的日常工作中,我们经常面临一个至关重要的挑战:安全性审计。你是否遇到过这样的情况:一个新项目上线,或者到了年底审计的时候,你需要准确回答“谁在这个数据库里拥有什么权限?” 这听起来简单,但在复杂的数据库环境中,这往往是一项艰巨的任务。

为了确保数据的安全性和合规性,我们必须清楚地掌握每一个用户、每一个角色的访问级别。幸运的是,SQL Server 为我们提供了一套强大的内置系统函数和视图,让我们能够像透视眼一样看穿权限的分配情况。

在这篇文章中,我们将深入探讨如何利用 SQL Server 的系统目录视图和函数,来全面检索数据库中所有用户的权限。我们将不仅学习基础的查询方法,还会通过实战案例来理解背后的权限架构,并融入 2026 年最新的安全左移DevSecOps理念,分享一些在真实生产环境中非常有用的审计脚本。

为什么权限审计如此重要?

在开始写代码之前,让我们先达成一个共识:权限管理是数据库安全的基石。不恰当的权限分配可能导致数据泄露、误删甚至是系统瘫痪。到了 2026 年,随着数据隐私法规(如 GDPR、个人信息保护法)的严格执行,权限管理不再仅仅是 DBA 的工作,而是全开发生命周期的一部分。通过定期检查权限,我们可以:

  • 确保最小权限原则:确认用户只拥有完成工作所需的权限,不多也不少。
  • 发现僵尸账户:找出那些不再活跃但依然拥有高权限的账户,这在现代微服务架构中尤为重要,因为服务账户往往比人更多。
  • 合规性报告:满足 ISO、SOX 或内部安全审计的要求,实现合规即代码。

核心工具:SQL Server 的元数据与现代 IDE 实践

SQL Server 存储了所有关于用户、角色和权限的信息在系统视图中。为了查询这些信息,我们通常会用到以下几种方式。但在我们深入代码之前,值得一提的是,现代开发环境已经发生了变化。我们现在可能会使用 CursorWindsurf 这样的 AI 原生 IDE 来编写这些 SQL 查询。

AI 辅助工作流提示:如果你在 Cursor 中编写复杂的审计脚本,你可以尝试这样向 AI 下达指令:“分析当前的 sys.database_permissions 视图,并生成一个能够递归查找角色嵌套权限的存储过程。” 这种 Vibe Coding(氛围编程) 的方式能极大提高我们编写元数据查询的效率。

现在,让我们看看核心的系统视图:

  • sys.fn_my_permissions: 这是一个非常实用的函数,主要用于查看特定安全主体(也就是用户或角色)对某个对象拥有哪些权限。
  • sys.fn_builtin_permissions: 这个函数返回服务器或数据库中所有可能的权限定义列表,相当于 SQL Server 的“权限字典”。
  • INLINECODEa79c0dde 和 INLINECODE0fe6c86f: 分别用于查看数据库级和服务器级的所有主体(用户、组、角色)。
  • sys.database_permissions: 这是查询权限分配最核心的视图,它记录了谁对谁做了什么。

让我们一步步来探索如何使用这些工具。

方法一:快速检查当前上下文的权限

首先,让我们从一个最简单的场景开始。假设你刚刚以数据库管理员的身份连接到数据库,你想知道当前登录用户到底“能做什么”。这时,sys.fn_my_permissions 就派上用场了。

这个函数接受两个参数:安全对象类安全对象路径。如果我们传入 NULL,它会列出当前数据库的权限。

查询示例 1:查看当前用户对数据库的权限

-- 查询当前用户对当前数据库的所有权限
-- 这是一个很好的起点,用于验证当前连接的身份上下文
SELECT 
    entity_name AS [对象名称],
    subentity_name AS [子对象名称],
    permission_name AS [权限名称],
    state_desc AS [状态描述]
FROM fn_my_permissions(NULL, ‘DATABASE‘);

代码解析:

当你运行这段代码时,SQL Server 会检查当前登录上下文。INLINECODE086c5612 列通常会显示 INLINECODEfb468ddb(已授予)或 INLINECODE8a1edd1d(已拒绝)。如果你看到 INLINECODEe4a32461,请注意,INLINECODEf4eff7e2 的优先级最高,它会覆盖所有的 INLINECODE81c89d6b。这在排查故障时非常有用——如果你明明被授予权限却无法操作,请先检查这里是否有 DENY

进阶实战:全量用户权限审计(生产级脚本)

虽然在特定的调试场景下 fn_my_permissions 很有用,但作为一名 DBA,你更需要的是“上帝视角”:一次性列出数据库中所有用户及其对应的权限

仅仅使用 fn_my_permissions 是无法做到这一点的,因为它只能查看“当前用户”。要查看所有用户,我们需要联接系统视图。但在 2026 年,我们的要求更高:不仅要看直接权限,还要考虑性能和可读性。

查询示例 5:全方位权限审计脚本(企业级优化版)

这是本文中最核心、最实用的查询。我们不仅列出了权限,还加入了对象类型的判断,使其输出更加易于阅读。

-- 这是一个通用的权限审计查询(针对当前数据库)
-- 它会列出当前数据库中所有被明确授予权限的用户和角色
-- 特性:过滤系统噪音,格式化对象名称
USE [YourDatabaseName]; -- 请替换为你的数据库名
GO

SET NOCOUNT ON; -- 减少网络流量,提升性能

SELECT 
    princ.principal_id AS [用户ID],
    princ.name AS [用户名称],
    princ.type_desc AS [用户类型], -- 比如 SQL_USER, WINDOWS_USER, DATABASE_ROLE
    perm.state_desc AS [状态], -- GRANT, DENY, REVOKE (REVOKE 在此视图中通常不出现,除非显式定义)
    perm.permission_name AS [权限名称],
    CASE perm.class_desc
        WHEN ‘SCHEMA‘ THEN ‘Schema: ‘ + SCHEMA_NAME(perm.major_id)
        WHEN ‘OBJECT_OR_COLUMN‘ THEN OBJECT_SCHEMA_NAME(perm.major_id) + ‘.‘ + OBJECT_NAME(perm.major_id)
        WHEN ‘DATABASE‘ THEN DB_NAME()
        WHEN ‘TYPE‘ THEN TYPE_NAME(perm.major_id)
        WHEN ‘XML_SCHEMA_COLLECTION‘ THEN ‘XML Collection: ‘ + CAST(perm.major_id AS VARCHAR)
        ELSE perm.class_desc + ‘: ‘ + CAST(perm.major_id AS VARCHAR)
    END AS [目标对象],
    perm.class_desc AS [对象类型] -- SCHEMA, OBJECT, DATABASE 等
FROM 
    sys.database_principals princ
-- 这里使用 LEFT JOIN 确保即使没有权限的用户也能被列出(如果是做全量审计)
-- 但为了权限列表的清晰度,这里我们关注已分配的权限
INNER JOIN 
    sys.database_permissions perm ON perm.grantee_principal_id = princ.principal_id
WHERE 
    -- 过滤掉系统默认账户,减少干扰
    princ.name NOT IN (‘dbo‘,‘guest‘,‘public‘,‘sys‘,‘INFORMATION_SCHEMA‘, ‘MS_AgentSigningCertificate‘)
    -- 过滤掉固定的数据库角色(如 db_accessadmin),除非你想审计谁被修改了固定角色
    AND princ.is_fixed_role = 0 
ORDER BY 
    princ.name, 
    perm.class_desc, 
    perm.permission_name;

深度解析:

  • 可读性增强:我们使用了 INLINECODE8faf7d6d 语句来处理 INLINECODEe0cf6549。原本的 INLINECODEa83a1d7b 只是一个数字,对人类来说毫无意义。现在,它会显示为 INLINECODEb6badd5a 或 dbo.Table1,这在导出报告给非技术人员(如安全审计员)查看时非常友好。
  • INNER JOIN vs LEFT JOIN:在这个特定查询中,为了专注于“谁有权限”,我们使用了 INLINECODEe232395e。如果你需要找出“哪些用户没有任何权限”(这也是安全隐患),请改回 INLINECODEe2c3f39b 并在末尾添加 AND perm.permission_name IS NULL

2026 视角:处理角色嵌套与 RBAC 的复杂性

你可能会发现,上面的查询漏掉了一部分东西。如果你使用的是基于角色的访问控制(RBAC)——这是现代安全架构的黄金标准——用户本身可能没有任何直接授予的权限,他们是通过加入到某个角色(如 INLINECODEd3064cd9 或自定义角色 INLINECODEff4bd17e)来获得权限的。

仅仅查询 INLINECODE99a736ad 无法显示出用户继承自角色的权限。要解开这种嵌套关系,我们需要引入 INLINECODE09424812 视图。

查询示例 6:解析 RBAC 链条(综合审计)

下面的脚本不仅能看到直接授予的权限,还能看到用户属于哪个角色,并尝试解析 Windows 组成员(这是一个高级话题,通常需要调用 Active Directory,但在数据库层面我们先看现有关系)。

-- 查询用户及其所属的角色
-- 这有助于理解通过角色间接获得的访问权限
SELECT 
    ‘User‘ AS [Principal Type],
    u.name AS [用户名称],
    u.type_desc AS [用户类型],
    r.name AS [所属角色名称],
    u.is_disabled AS [是否禁用] -- 帮助发现僵尸账户
FROM 
    sys.database_principals u
-- 建立用户与角色的关联
INNER JOIN 
    sys.database_role_members rm ON u.principal_id = rm.member_principal_id
INNER JOIN 
    sys.database_principals r ON rm.role_principal_id = r.principal_id
WHERE 
    u.type_desc IN (‘SQL_USER‘, ‘WINDOWS_USER‘, ‘WINDOWS_GROUP‘)
    AND u.name NOT IN (‘dbo‘, ‘guest‘)
    AND u.principal_id > 4 -- 排除系统自带的 ID
ORDER BY 
    u.name, r.name;

实战建议: 在审计时,你需要结合这两个查询的结果。如果一个用户在查询 5 中没有任何 INLINECODE3e83d083,但在查询 6 中出现在了 INLINECODE6103a144 角色里,那么这个用户实际上拥有对所有表的读权限。这符合我们的Agentic AI 逻辑:将复杂的权限系统分解为明确的层级关系,自动化地判断最终访问权。

边界情况与容灾:当查询失效时

在我们的生产环境中,遇到过一种极端情况:当数据库处于 SUSPECT(可疑)状态或正在从备份还原时,部分系统视图可能不可用。此外,对于 Always On 可用性组 的辅助副本,只能进行读操作,修改权限的操作会被阻止,但查询权限通常是允许的。

常见陷阱与性能优化:

  • 不要在生产高峰期运行全量 JOIN:如果你有成千上万个数据库对象和数万个权限记录,上述的复杂 JOIN 可能会阻塞元数据访问。建议在业务低峰期运行。
  • 警惕“所有权链”:上面的脚本查询的是显式权限。但是,如果用户拥有对 Schema 的 INLINECODEa093c046 权限,他们实际上拥有该 Schema 下所有对象的所有权限,即使 INLINECODEdbd99dc6 里没有记录。这是我们常说的“隐式权限”。

为了捕获这种隐式权限,我们需要一个更复杂的脚本,或者使用 Extended Events (扩展事件) 来追踪权限被拒绝的错误日志,从而反向推断权限漏洞。

现代化部署:将审计纳入 CI/CD

在 2026 年的今天,手动运行脚本已经过时了。我们应该将权限审计自动化。以下是我们推荐的 DevSecOps 流程:

  • 基础设施即代码:将数据库角色和权限的定义存储在 SQL 脚本或 Terraform 配置中,而不是在 SSMS 图形界面中点点点。
  • 自动化检查:在 CI/CD 流水线(如 GitHub Actions 或 Azure DevOps)中加入一个步骤,运行本文提供的审计脚本,并将输出与“金标准”权限配置进行比对。
  • 自动警报:如果发现偏差(例如有人直接在生产环境修改了权限),流水线应失败并发送警报给团队。

故障排查技巧:如果你发现某个用户可以做意料之外的操作(比如删表),但他本身没有显式权限,请检查他是否属于 INLINECODE5f0fc1a5 或 INLINECODEe7dffb66 角色,或者检查他是否拥有该表的 ALTER 权限。

总结

掌握 SQL Server 的权限查询不仅仅是为了应付审计,更是为了保障我们数据资产的安全。通过巧妙地结合 INLINECODE21ca0564、INLINECODEa58e1541 和 sys.database_permissions,我们可以从任意角度审视数据库的安全状态。

在这篇文章中,我们学习了:

  • 如何使用 fn_my_permissions 快速检查特定权限。
  • 如何编写生产级的综合查询来列出所有用户及其在数据库中的实际权限状态。
  • 如何处理复杂的角色嵌套和隐式权限
  • 如何将这些实践融入现代化的 DevSecOps 流程。

下一步建议:

你可以尝试将文中提供的 SQL 脚本保存为常用的管理模板。此外,建议定期(例如每季度)执行一次全量的权限审计,并将结果导出保存。记住,安全不是一个静态的状态,而是一个持续的过程。让我们利用这些工具,让我们的数据库环境更加透明、安全。

希望这些深入的解析和实战脚本能让你的工作更加得心应手!如果你有任何关于特定权限场景的疑问,或者想了解如何用 Cursor 让 AI 帮你写这些脚本,欢迎继续探讨。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/19828.html
点赞
0.00 平均评分 (0% 分数) - 0