一、前言
本篇文章主要说一说SQLServer数据库中访问控制控制点涉及到的SQLServer基础知识,本来想和对测评项的理解写在一起的,但是发现这样篇幅过长,且SQLServer的权限结构有点绕,不利于阅读和吸收,所以就分开来写了(写完之后我自己都有点晕了)。
对于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权限结构的一部分(基础)内容,其余的大家根据需要自行去探索吧。
*本文作者:起于凡而非于凡,转载请注明来自FreeBuf.COM
来源:freebuf.com 2020-04-10 09:00:34 by: 起于凡而非于凡
请登录后发表评论
注册