一、前言
对于sqlserver的权限管理,我从接触初始就感觉到迷惑,登录名、服务器角色我懂,但是数据库用户是用来干嘛的?架构又是用来干嘛的?数据库角色和架构是重名的,有什么特殊关系吗?权限到底是如何传递、判断的?用户的默认架构又是怎么回事……
趁着春节假期,花时间把这些东西从头到尾捋了捋,希望对大家能够有所帮助。
二、SQLServer的权限分配
先对SQLServer的权限分配进行基本介绍,如果对这个不清楚的话,那么访问控制控制点的测评实际上也没办法进行。
2.1. 基本概念
SQLServer在权限方面的构造有一点点绕,容易迷惑人,要从基本的概念说起。
涉及到SQLServer权限的有登录名、服务器角色、数据库用户、数据库角色、架构等。
注意,该文章可能比较枯燥,但比较实用,网上其它文章虽然写得深入得多,但是未必这么详细。
2.2. 登录名
登录名也就是一般意义上的账户,包括SQLServer中的账户和Windows操作系统登录名:
使用登录名登录之后,才可以访问数据库实例。
2.3. 服务器角色
角色大家都知道,即一系列权限的**,而拥有角色的账户,也就拥有了这一系列的权限。
而SQLServer的服务器角色,顾名思义,也就是服务器级别的角色,对该服务器的所有数据库均具备权限。
其具体角色和权限如下:
在SQLServer这里,服务器角色的拥有者只能是登录名,右键点击某一服务器角色,选择属性,在角色成员列表下方点击添加,在弹出来的窗口中选择对象类型,我们会发现只存在登录名这一对象类型:
另外,服务器角色中的角色是固定的,不能创建和删除(不存在该选项):
服务器角色的权限,除了public以外,也都是固定的:
将登录名添加到服务器的角色成员(即拥有该角色的权限),可以在服务器角色的属性中添加(如上文所展示的),也可以在登录名的属性中添加:
这里要注意的是,public是一个特殊的服务器角色,所有登录名默认拥有该角色,且不可更改(即强制拥有public角色的权限)。
那么,对public赋予过多的权限,就意味着权限失控。
public的默认权限为VIEW ANY DATABASE,网上的文章都这么说,这是对的。
但是你真的跑去查看public的权限时,是看不到这个权限的:
实际上需要在安全对象中添加当前服务器,才能看到该权限和进行设置:
好,服务器角色的介绍先到此为止。
其实服务器角色这个层面的话,是比较容易理解的,因为它就是用户-角色-权限的常见模型。
2.4. 架构
先来说架构,架构包含数据库对象,如表、视图和存储过程,可以理解为数据库对象的**。
上面是一种描述,其直观的体现为是数据库表的名字,从SQLServer2005开始,一个数据库表的完全限定名称为,server.database.schema.object也就是服务器.数据库.架构.对象。
我这里创建了一个数据库,名为TestDB,其默认存在的架构如下(T1是我自己创建的):
在创建数据库表的时候,就要给它指定一个架构,可以是默认的架构,也可以是自己创建的架构:
这里我选择了架构T1,一般默认选择的架构是dbo。
好,架构说到这里,大家记住,某数据库表属于某架构。
2.5. 数据库角色
每个数据库都拥有自己的角色,为数据库级别的角色,如下图:
首先,数据库角色也是拥有一定的权限的,不过是数据库级别的权限:
数据库角色中可以自创角色,但是默认存在的数据库角色除了public以外,其它角色的直接权限不可更改。
数据库角色public和服务器角色public有些类似,在数据库一级,所有(数据库)用户均属于public角色。
大家注意看,数据库角色和架构中有很多是重名的:
其实它们没有什么特殊的关系,只是在默认情况下,比如角色db_owner,默认为架构db_owner的拥有者而已,你也可以将架构db_owner的拥有者改成其他的数据库用户或者数据库角色:
那么拥有某架构是什么意思呢?拥有某架构其实就代表拥有了这个架构下数据库对象(比如数据库表)的所有权限。
但是架构的拥有者只能是某一个数据库角色或者某一个数据库用户,但可以实现间接拥有。
比如角色A拥有架构B,数据库用户C属于角色A,那么数据库用户C也拥有架构B。
2.6. 数据库用户
每个数据库都拥有自己的用户,是数据库级别的,如下图:
数据库用户是用来干啥的呢?
它是用来承上启下的,登录名不能直接访问数据库对象,它需要和被访问数据库的数据库用户进行映射,然后使用数据库用户的权限来进行操作:
三、权限分配实际例子
理论说得多没有用,还是用实际的例子来说,一看就明白了。
存在登录名TestLogin,存在数据库TestDB,数据库中的数据库用户为默认用户,数据库中存在数据库表TestTable,数据库表的架构为T1,其拥有者为数据库用户dbo,服务器角色public权限为默认权限,数据库角色public的权限为默认权限。
登录TestLogin,此时由于TestDB中仅存在默认数据库用户,TestLogin无映射的数据库用户,无法访问TestDB。
注:实际映射了guest用户,但guest用户现在无权限,guest用户的内容在数据库默认用户中进行说明。
创建TestDB的数据库用户TestUser,映射TestLogin,TestUser此时不拥有任何架构,不属于任何角色:
此时TestUser默认属于数据库角色public,拥有一定的权限,但是对于TestTable表不具备任何权限:
数据库角色Public对于TestTable表无任何权限:
对于其它视图具备选择权限:
此时直接查询TestTable,会显示权限不足:
下面说明获得权限的几种方法,以查询权限为例。
3.1. 方法一
在服务器角色层面获得权限
比如将sysadmin授予TestLogin登录名:
此时,由于sysadmin具备所有权限,TestLogin自然就获得了查询权限:
注:这里比较特殊,属于sysadmin的登录名会映射到每个数据库内的dbo用户(该属于数据库的db_owner角色),所以此处和TestUser没啥关系,如果不存在TestUser,但只要TestLogin属于sysadmin,TestLogin仍具备权限。这部分具体内容在数据库默认用户中说明。
这里也可以给服务器角色public设置相应权限(如控制服务器权限),使得TestLogin获得相应权限。
3.2. 方法二
在数据库角色层面获得权限
将TestLogin从sysadmin中移除,将数据库角色db_datareader赋予TestUser:
由于db_datareader的权限为从所有用户表中读取所有数据,故TestUser获得了查询权限。
这里是因为TestUser获得了数据库级别的读取权限:
这里也可以让数据库角色public设置相应权限,使得TestUser获得相应权限。
3.3. 方法三
直接拥有某架构,从而获得架构的权限
将TestUser从db_datareader中移除,再将架构T1的所有者改为TestUser:
则此时TestUser拥有了T1架构的全部权限,自然就拥有了查询权限:
3.4. 方法四
间接拥有某架构,从而获得架构的权限
将T1的所有者改为db_datawriter,再将db_datawriter赋予TestUser,则相当于TestUser间接拥有了T1架构,也就拥有了查询权限:
注意,这里和db_datawriter本身的权限无关,db_datawriter为写的权限,如果此处不是TestUser间接拥有了T1架构,仅仅是获得了db_datawriter的权限,则不可能具备查询权限。
这里也可以让数据库角色public拥有T1,则TestUser会间接拥有了T1架构。
3.5. 方法五
获取表级权限
先进行重置:将T1的所有者改回数据库用户dbo,再将TestUser从db_datawriter中移除。
在数据库表的属性中可直接对数据库用户或数据库角色public进行权限设置:
这里对TestUser的权限进行设置,授予其选择权限,其中有效选项卡中即为其权限,列字段代表涉及到的数据库列(TestTable只有一个列test):
则此时,TestUser具备了TestTable的查询权限。
这里的权限,可以在数据库表的属性中进行设置,也可以在TestUser的属性中进行设置,是同一个意思:
注意:上图中授予和拒绝的选项框是互斥的。
3.6. 方法六
直接获取架构级的权限
还可以在架构级进行权限,其实和表级权限是一样的,也是在架构的属性或者数据库用户的属性中进行设置:
这里有一个优先级和权限传递的关系。
比如我在T1架构处赋予了TestUser选择权限,则取查看TestTable属性时,其显示选项卡虽然不会有任何变化:
但是其有效选项卡会显示实际具备的权限,TestUser具备对TestTable的查询权限:
如果是T1处将选择权限设置为拒绝,那么在TestTable处将选择权限设置为授予也没啥用,TestUser照样不具备对TestTable的选择权限。
又或者,T1处将选择权限设置为授予,在TestTable处将选择权限设置为拒绝,TestUser仍然不具备对TestTable的选择权限。
所以,SQLServer的权限判断模式,应该是从上至下,一级一级的判断,其中任何一级只要设置了拒绝,那么对于某对象就不具备该权限。
如果表具备多列的话,还可以设置列级权限:
上图中,TestTable增加了test2列,将test列的选择权限设置为拒绝。
则最后的权限为:
实际查询时返回错误如下:
3.7. 方法七
直接获取数据库级的权限
数据库级别的权限设置,在数据库的属性中,可以设置数据库级别的权限:
TestUser默认具备的权限是连接,那么这个和成为数据库角色的成员再获得权限有啥区别呢?
应该没啥区别,仅仅是SQLServer支持这两种权限设置的方式而已。
一种是直接将单个权限授予给数据库用户,一种是通过角色来间接授予权限。
3.8. 方法八
直接获取服务器级的权限
服务器级别的权限设置,服务器属性中也可以进行单项权限的设置:
3.9. 方法九
直接拥有某数据库,从而获得数据库的权限
数据库的拥有者只能是登录名,且其拥有者即为数据库用户dbo映射的登录名,默认情况下,该登录名为sa。
可以在数据库属性中对其拥有者进行更改:
此时,数据库用户dbo映射的登录名也将会变成TestLogin:
数据库dbo用户默认属于db_owner角色,且不可撤销:
所以,TestLogin也就自然获得了权限。
四、默认数据库用户
在创建一个数据库后,会默认存在dbo、guest、INFORMATION_SCHEMA、sys账户:
4.1. dbo用户
dbo的全程应该是:database owner,即数据库所有者。
其默认映射的登录名为sa,其属于的数据库角色为db_onwer
其属于的数据库角色不可改变,其映射的登录名可以在数据库属性中进行更改:
dbo用户可以属于多个登录名(但是不会在数据库用户属性中显示出来):属于sysadmin服务器角色的登录名会直接映射到每个数据库内的dbo用户。
4.2. guest用户
guest用户默认应该没有权限,或者顶多默认具有连接权限。
当一个登录名在某一个数据库中没有映射的数据库用户时,将会映射到guest用户中,具备guest用户的权限。
比如TestLogin如果在TestDB中不具备映射的数据库用户时,它将映射到guest用户中,此时若guest用户属于db_onwer数据库角色,那么TestLogin也获得相关权限。
当一个登录名在某一个数据库中存在映射的数据库用户时,就不会映射到guest用户中了,也不会具备guest用户的权限。
比如TestLogin如果在TestDB中存在一个映射的数据库用户TestUser,此时就与guest用户无关了,guest用户属于db_onwer数据库角色,TestLogin也不会具备相关权限。
在登录名的属性中,可以看到某个数据库的guest用户是否被启用:
注意,这里的所谓启用还是不启用,仅仅是指在数据库属性中,是否赋予了guest用户连接属性。
如果在数据库属性中赋予了,此处的选项框就会被勾选。
而且好像仅仅只认同这一个方式的权限赋予,比如在guest用户属性中,将guest用户添加为db_onwer的成员,此时guest用户已经具备了数据库的所有权限。
但是在这里的选项框处,仍然不会显示被勾选。
4.3. 其他默认账户
也就是information_schema、sys,这两个默认用户拥有两个默认框架information_schema、sys,这两个默认框架包含内容如下:
但是这两个用户到底映射哪些登录名,我是真没搞明白……
五、应用程序角色
这个还是单独说吧,在数据库内可以创建应用程序角色:
可以看到,应有程序角色不包括成员,且需要设置密码。
应用程序角色说明如下:
Microsoft® sql server™ 中的安全系统在最低级别,即数据库本身上实现。无论使用什么应用程序与 SQL Server 通讯,这都是控制用户活动的最佳方法。但是,有时必须自定义安全控制以适应个别应用程序的特殊需要,尤其是当处理复杂数据库和含有大表的数据库时。
此外,可能希望限制用户只能通过特定应用程序(例如使用 SQL 查询分析器或 Microsoft Excel)来访问数据或防止用户直接访问数据。限制用户的这种访问方式将禁止用户使用应用程序(如 SQL 查询分析器)连接到 SQL Server 实例并执行编写质量差的查询,以免对整个服务器的性能造成负面影响。
其特征如下(在 SQL Server 中创建应用程序角色):
使用应用程序的方法:sp_setapprole (Transact-SQL)
其余的就不进行更多说明了,因为在SQLServer中进行权限设置的人本来就不多,使用应用程序角色这个功能的人就更少了。
六、其他说明
6.1. 数据库角色的所有者
数据库角色有一个所有者属性,这个属性不知道有什么用。
在默认状态下,将db_owner的所有者改为TestUser,TestUser不会具备db_owner的权限:
6.2. 默认架构
另外,TestLogin登录名会的属性中,有一个默认架构:
这个默认架构也不会赋予登录名或数据库用户什么权限,仅仅是在执行SQL语句时,如果涉及到该数据库的具体表名时,会自动给你加上(默认架构)前缀而已。
比如TestTable属于T1架构,由于TestUser的默认架构是dbo,所以直接执行下述SQL语句,会显示这样的错误:
需要手动加上前缀:
如果将TestUser的默认架构改成T1,也就不用手动加前缀了:
6.3. 重名
在SQLServer的权限结构中,会出现很多重名现象,比如架构和数据库角色的重名上面已经说过了,还存在着架构和数据库用户的重名。
比如:
不过dbo架构无法修改所有者,强制为dbo用户,仅此而已。
6.4. 版本差异
在2000中,假如有一个账户tt在test数据库中创建了一张表table1的时候,在服务器上对查询的语句应为select * from test.tt.table1,也就是说,在sqlserver 2000中一张表所属的架构默认就是表的创建者的登录名称,用户可以和修改他所创建的所有数据库对象。
在 SQL Server 2005 中,架构和创建它的数据库用户不再关联,完全限定名(fully-qualified name)现在包含4个部分:server.database.schema.object
另外,对于服务器角色public,如果在SQLServer 2005上面没有发现的话,那么很可能是因为你没有安装sql server的补丁包(sql server 2005 sp2)。
七、总结
通篇写下来,好像SQLServer的权限结构和其它数据库没多少区别。
但是SQLServer数据库在中间搞了个数据库用户,而且又存在大量的重名现象,很容易把人搞晕了。
下面做了个简图,大概的描述了下权限结构:
SQLServer的权限判断模式,应该是从上至下,一级一级的判断,其中任何一级只要设置了拒绝,那么对于某对象就不具备该权限。但对属于sysadmin的成员不做任何权限判断,换句话说,sysadmin组的成员可以为所欲为。
SQLServer可以控制到数据库表中列一级的权限。
SQLServer所有登录名均为服务器角色public的成员,所有数据库用户默认为数据库角色public的成员。
SQLServer中所有属于sysadmin服务器角色的登录名会直接映射到每个数据库内的dbo用户。
SQLServer中对于某一个登录名而言,如果某个数据库中无映射的数据库用户,那么将会映射到数据库guest用户中。
最后,这里对于架构中的对象只说了数据库表,视图和存储过程没有说,但是它们的权限判断模式基本差不多,就不写了。
另外,我这篇文章也只是介绍了SQLServer权限结构的一部分(基础)内容,其余的大家根据需要自行去探索吧。
一、测评项
a)应对登录的用户分配账户和权限;
b)应重命名或删除默认账户,修改默认账户的默认口令;
c)应及时删除或停用多余的、过期的账户,避免共享账户的存在;
d)应授予管理用户所需的最小权限,实现管理用户的权限分离;
e)应由授权主体配置访问控制策略,访问控制策略规定主体对客体的访问规则;
f)访问控制的粒度应达到主体为用户级或进程级,客体为文件、数据库表级;
g)应对重要主体和客体设置安全标记,并控制主体对有安全标记信息资源的访问。
二、测评项a
a)应对登录的用户分配账户和权限;
3.1. 测评项要求1
如果从字面意思来看,就是一个废话,用户都登录账户了,自然就存在着账户。
这里的意思是应该是你本来就存在“多个账户”,然后当用户使用时要适当的“分配账户”给用户,而账户再拥有不一样的权限,这样就实现了将权限通过账户分配给用户(自然人)。
所以,该测评项就需要SQLServer中存在两个账户,且这两个账户的权限不一样。
在SQLServer中,所谓的账户就是登录名:
3.2. 测评项要求2
在测评要求中测评实施如下:
在SQLServer中,其默认账户不少,主要应该关注那种会造成权限失控的账户或角色。
sa登录名
sa登录名,是SQLServer的默认登录名,强制(无法更改的)属于服务器角色sysadmin的成员,拥有服务器的所有权限。
对于这个测评项,所谓的限制权限就是直接禁用sa登录名,这个倒不是一定需要,看业务需求。
服务器角色public
服务器角色public,默认存在,且不能删除。
SQLServer所有登录名均为服务器角色public的成员,也即所有登录名均拥有服务器角色public的权限。
默认情况下,服务器角色public的权限仅为查看任意数据库:
所以默认情况下,服务器角色public的权限就基本已经实现最小化了,核查一下即可。
数据库角色public
数据库角色public,默认存在,且不能删除。
所有数据库用户默认为数据库角色public的成员,也即所有数据库用户均拥有数据库角色public的权限。
默认情况下,数据库角色public的不拥有任何架构,查看某数据库角色或数据库用户拥有的架构的语句为如下:
SELECT * FROM sys.schemas WHERE principal_id = DATABASE_PRINCIPAL_ID('public')
也可以用过图形化界面查看,不过感觉不如SQL语句,因为存在滑动条,还得滚动滑动条才能看到全部情况:
默认情况下,数据库角色public拥有数据库中一部分系统视图的选择权限,不具备对用户自建表的权限,其查询语句如下:
select princ.name , princ.type_desc , perm.permission_name , perm.state , perm.state_desc , perm.class_desc , object_name(perm.major_id) from sys.database_principals princ left join sys.database_permissions perm on perm.grantee_principal_id = princ.principal_id where princ.name='public'
注意:sys.database_permissions视图里存储的是数据库主体如数据库用户、数据库角色对具体的数据库对象如数据库表、架构等存在的直接权限。
间接权限不会显示在里面,如数据库用户A属于数据库角色B,那么A就拥有B的权限,但sys.database_permissions视图中A的权限数据不会有变化。
对于直接权限,也可以通过界面查看:
嗯,从现有的角度来看,数据库角色public也没拥有啥权限,比如对于sys.all_columns就没有权限,也就无法得知用户自建表的结构,应该算是权限最小化了。
数据库用户guest
数据库用户guest默认存在,且不能删除。
SQLServer中对于某一个登录名而言,如果某个数据库中无映射的数据库用户,那么将会映射到数据库Guest用户中。
数据库用户guest默认拥有架构guest:
数据库用户guest默认不属于其它数据库角色(除了public),用户新建的数据库中对于数据库默认也不具备任何权限:
不过在master数据库中具有选择权限:
对于数据库用户guest而言,默认情况也是最小权限。
总结
对于这些默认服务器角色、数据库用户 、数据库角色,主要检查是否仅拥有小的权限。
三、测评项b
b)应重命名或删除默认账户,修改默认账户的默认口令;
SQLServer中默认的登录名是sa,虽然好像有方法可以修改sa的用户名,但似乎不应该强制被测评单位实现。
至于默认口令,sa不存在默认口令,初始口令是在安装数据库时设置的。
四、测评项c
c)应及时删除或停用多余的、过期的账户,避免共享账户的存在;
首先说一说多余账户,一般是先访谈,问对方某账户是干啥用的。
如果对方答不上来,你自己通过核查也无法判断,那么这就是多余账户(或者叫不明用途的账户)。
而避免存在共享账户,即不能多人使用同一个账户。
但如果一人使用多个账户的话,虽然不属于共享账户的情况,但是一人使用多个账户的情况意义何在?有存在多余账户的嫌疑。
五、测评项d
d)应授予管理用户所需的最小权限,实现管理用户的权限分离;
数据库和操作系统有些不一样的地方在于,数据库中的对象和应用程序的业务逻辑关联比较大。
除了一般意义上的数据库的管理账户,大概率还存在着一些应用程序使用的账户。
比如某应用程序功能模块连接数据库时使用的登录名只对某数据库的某些视图或者存储过程存在权限,等等。
对于要如何实现测评项的要求,个人感觉没有通用的要求模板,只要不是一个sa登录名从头用到尾(即只使用最高权限账户),或多或少都能符合一点要求,也就是部分符合。
那么怎么才算是符合呢?应该要根据应用程序业务复杂程度来判断吧,应用程序业务越复杂或者越庞大,则数据库账户的权限就应该划分得越细致。
如果不是特别简单的业务,比如只有一个数据库的那种,至少应该将权限先设置到数据库权限一级,而不是服务器权限一级。
也即权限直接针对具体的数据库,而不是对整个服务器具备权限。
至于具体的权限,如果仅仅针对该测评项,其实服务器角色和数据库角色中就有现成的模板,不是很需要自己创建角色:
看上图,比如数据库角色中,有具备纯写权限的角色、纯读权限的角色、备份数据库权限的角色等等。
至于如何查看某登录名在服务器、数据库、表(视图、存储过程)各个层级具体拥有的权限,可以看看这篇文章:数据库权限检查,另外再看看等保测评2.0:SQLServer访问控制(上),就差不多了。
六、测评项e
e)应由授权主体配置访问控制策略,访问控制策略规定主体对客体的访问规则;
所谓授权主体,即只有某个账户或者某一类账户具有权限来设置其它账户的权限。
可能拥有此类权限的账户为如下:
1.sa:默认账户,属于sysadmin角色,拥有服务器全部权限;
2.属于sysadmin角色的账户,拥有服务器全部权限;
3.数据库中属于db_owner角色的账户,拥有该数据库的全部权限;
4.某架构拥有者(用户或角色),可以设置该架构的权限;
5.db_securityadmin角色,为固定数据库角色,它的成员可以修改角色成员身份和管理权限。
6.直接被授予该权限的用户或角色。
这里就要看被测评方是否设置了这类角色了。
七、测评项f
f)访问控制的粒度应达到主体为用户级或进程级,客体为文件、数据库表级;
就是看权限控制粒度,对于客体,要看是否达到了数据库表的级别,也即单独对数据库表设置权限(视图、存储过程也可以),或者至少是否达到了架构级别(当然,不能只存在一个架构)。如果仅达到了数据库级别或者服务器级别的权限,那肯定是不符合要求的。
对于主体,要看是权限的设置是否直接针对某个登录名,在数据库级别,就要看是否直接针对某数据库用户。
八、测评项g
g)应对重要主体和客体设置安全标记,并控制主体对有安全标记信息资源的访问。
SqlServer自身应该不具备这个功能,可能要依靠操作系统或者第三方的什么软件来实现了。
关于安全标记,可以看看等保测评2.0:Windows访问控制中测评项g中的内容。
九、总结
其实测评项方面的理解相对于等保测评2.0:Windows访问控制没有什么新内容,这里主要是结合SQLServer的基础知识写了一些东西。
其实我也没有写得很明确,如果很明确的话应该以测评项指导书的格式来写。
但是这东西是没有一个固定的标准的,再说各个测评机构肯定都有自己的测评项指导书,我这里也就不献丑了。
,