1. SQL Server安全体系总览

在SQL Server中谈“数据安全”,不能只盯着某一张表或某一个登录名。SQL Server的安全模型是一个分层、可继承、可覆盖的体系:从最外层的Windows身份验证,到实例级登录名,再到数据库用户、架构、对象权限,每一层都有自己的“主体”和“安全对象”。理解这套体系的关键,是同时回答三个问题:谁在访问(主体)、访问什么(安全对象)、被允许做什么(权限)。这三者组合起来,才构成一条完整的授权链。

本节先建立整体框架,后续章节再逐层展开。我们用一个贯穿全篇的示例来理解:某公司有一台SQL Server实例,域账号 CORP\zhangsan 需要访问数据库 SalesDB 中的 dbo.Orders 表,并只能读取数据。这个看似简单的需求,实际上要穿过四道关卡。

一、主体:安全体系中的“谁”

主体(Principal)是能够请求SQL Server资源的实体。SQL Server的主体分为三个层级,理解层级是理解权限继承的前提。

  • Windows级主体:Windows登录名或Windows组,例如 CORP\zhangsan、CORP\DB_Readers。它们由操作系统验证身份。
  • 实例级主体:SQL Server登录名(Login),例如 CORP\zhangsan 映射的登录名,或SQL登录名 app_reader。登录名只负责“能否连上实例”。
  • 数据库级主体:数据库用户(User)、数据库角色、应用程序角色。例如 SalesDB 中的用户 zhangsan。用户负责“在数据库里是谁”。

这里最容易混淆的是登录名与用户:登录名属于实例,用户属于数据库。一个登录名可以在多个数据库中映射为不同名称的用户,也可以在某些数据库中没有用户——没有用户,就连不上该数据库,即使登录名本身有效。

二、安全对象:被保护的“什么”

安全对象(Securable)是权限可以授予的客体。SQL Server的安全对象同样分层:

  • 服务器级:服务器本身、端点、可用性组、服务器角色等。
  • 数据库级:数据库、架构、数据库角色、证书、非对称密钥等。
  • 架构级:架构是对象的容器,也是权限继承的重要节点。
  • 对象级:表、视图、存储过程、函数、列等。

权限可以在任意层级授予,并沿层级向下继承。例如在架构 dbo 上授予 SELECT,则该架构下所有表默认都获得查询权限;若只想放开一张表,就应在表级授予,而不是在架构级放开。

三、身份验证与授权:两道不同的门

身份验证(Authentication)解决“你是不是你声称的那个人”,授权(Authorization)解决“你能做什么”。SQL Server支持两种身份验证模式:

  • Windows身份验证:由Windows完成身份验证,SQL Server信任其结果。安全性高,支持组管理和密码策略。
  • SQL Server身份验证:由SQL Server自己校验登录名和密码。适合跨域、旧系统或应用专用账号。
  • 混合模式:同时允许上述两种,是生产环境常见配置。

身份验证通过后,进入授权阶段。授权的基本单位是“权限”,如 SELECT、INSERT、EXECUTE、CONTROL。权限可以授予(GRANT)、拒绝(DENY)、收回(REVOKE)。其中 DENY 优先级最高:即使通过角色继承了允许,只要在更具体层级存在DENY,最终结果就是拒绝。这是排查“为什么明明给了权限还是访问不了”的第一检查点。

四、权限层次与继承关系

把上述内容串起来,就得到一条从实例到对象的授权链。下图展示了示例账号 CORP\zhangsan 访问 SalesDB.dbo.Orders 的完整路径,以及每一层需要满足的条件。

SQL Server 安全架构:从实例到对象的授权链 示例:CORP\zhangsan 访问 SalesDB.dbo.Orders(仅读取) ① Windows 身份验证层 CORP\zhangsan Windows 验证身份 → 生成安全令牌 主体类型:Windows 登录名 ② 实例级:登录名(Login) Login: CORP\zhangsan 检查:登录名是否存在、是否启用、是否被 DENY CONNECT 安全对象:服务器 ③ 数据库级:用户(User) User: zhangsan 检查:登录名是否映射为用户、用户是否属于角色 安全对象:SalesDB ④ 架构级 / 对象级:权限(Permission) Schema: dbo Object: dbo.Orders GRANT SELECT 最终判定:允许读取 ⚠ DENY 优先级最高:若在表级存在 DENY SELECT,则即使架构级 GRANT SELECT,最终仍为拒绝 权限继承方向 ↓

图中可以看到,一次成功的访问需要四层同时成立:Windows身份有效、登录名存在且可连接、数据库用户存在且映射正确、对象权限允许。任何一层缺失或存在DENY,访问都会失败。排查权限问题时,按这个顺序逐层检查,比盲目尝试GRANT要高效得多。

五、角色:权限治理的规模化手段

如果为每个用户单独授予权限,用户一多就会失控。SQL Server提供角色(Role)作为权限的集合容器,分为固定服务器角色、固定数据库角色和用户自定义角色。推荐做法是:权限授予角色,用户加入角色,而不是直接授予用户。例如创建自定义角色 role_order_reader,授予其对 dbo.Orders 的 SELECT,再把 zhangsan 加入该角色。这样新增读者时只需加角色成员,权限模型保持稳定。

固定角色如 db_datareader 可快速赋予整库读取权限,但粒度太粗,生产环境通常只用于只读报表库或临时排查,不建议作为业务权限的长期方案。

六、最小权限与权限审计

安全体系的设计目标不是“能连上就行”,而是最小权限:只给完成工作所必需的权限,且尽量在更细粒度上授予。实现最小权限的常用手段包括:用架构隔离对象、用角色批量管理、用存储过程封装数据访问(只授予 EXECUTE 而不授予表权限)、对敏感列使用列级权限或动态数据掩码。

权限建立后还需要能查。SQL Server提供若干系统视图用于审计:sys.server_principals 查看实例级主体,sys.database_principals 查看数据库级主体,sys.database_permissions 查看数据库内显式权限,sys.fn_my_permissions 查看当前主体在指定对象上的有效权限。例如要确认 zhangsan 对 dbo.Orders 的有效权限,可以执行:

EXECUTE AS USER = 'zhangsan';
SELECT * FROM sys.fn_my_permissions('dbo.Orders', 'OBJECT');
REVERT;

结果中若出现 SELECT,说明读取权限已生效;若为空或只有 CONNECT,则说明授权链在某一层断了。这种“以目标用户身份验证有效权限”的方法,比逐条查看GRANT语句更接近真实访问结果,是权限治理中非常实用的手段。

七、本节要点回顾

  • 主体分Windows、实例、数据库三层,登录名与用户不是一回事。
  • 安全对象分服务器、数据库、架构、对象四级,权限沿层级继承。
  • 身份验证解决“你是谁”,授权解决“你能做什么”,两者不可混为一谈。
  • DENY优先于GRANT,是权限排查的首要检查点。
  • 用角色管理权限,用系统视图和 EXECUTE AS 验证有效权限,是权限治理的基本功。

掌握这套分层模型后,后续无论是配置登录名、设计数据库角色,还是排查“访问被拒绝”,都可以沿着“主体—安全对象—权限—继承与DENY”这条主线定位问题,而不是停留在零散的命令记忆上。