第5章SQLServer2012安全,怎么查看数据库密码

密码 19
第5章SQLServer2012安全 随着网络时代的到来,越来越多的业务系统运行在互联网上,越来越多的数据都以比特的方式保存在硬盘上,数据的安全成了人们日益关注的一个问题。
作为一款强大的企业级数据库管理系统,SQLServer在安全方面做了很多的工作。
本章将主要讲解SQLServer2012在安全方面的特性。
5.1新安全机制概论 可将保护SQLServer视为一系列步骤,它涉及4方面:平台、身份验证、对象(包括数据)及访问系统的应用程序。
本节将从这4个方面进行简单的介绍。
5.1.1平台与网络安全性 SQLServer的平台包括物理硬件和将客户端连接到数据库服务器的联网系统,以及用于处理数据库请求的二进制文件。
物理安全性的最佳实践是严格限制对物理服务器和硬件组件的接触。
例如,将数据库服务器硬件和联网设备放在限制进入的上锁房间。
此外,还可通过将备份媒体存储在安全的现场外位置,限制对其接触。
实现物理网络安全首先要防止未经授权的用户访问网络。
具体实现包括以下几点。

1.关闭不必要的网络协议 在第1章讲解SQLServer2012的协议中已经讲到,SQLServer2012支持4种不同的协议进行连接。
如果资源有限,SQLServer与应用程序是在同一台服务器上(当然,这是一种不推荐的做法),此时就可以只启用SQLServer的共享内存协议,而将其他协议关闭。
只开启共享内存协议后,没有任何人可以通过网络直接连接SQLServer,当然也就提高了网络安全性。
如果SQLServer服务器和应用程序服务器是在同一个局域网中(例如服务器之间使用网线直接连接)如图5.1所示,则对外暴露的只有应用程序服务器,数据库服务器与应用程序服务器在同一个局域网中,此时只需开启命名管道协议即可。

2.指定并限制用于SQLServer的端口 由于网络架构原因或其他因素需要将SQLServer服务器直接暴露在因特网上,如果使用默认的SQLServer端口1433将是十分危险的。
黑客通过端口扫描便可断定扫描到的服 第5章SQLServer2012安全 务器是数据库服务器,通过利用系统漏洞、SQL注入或利用木马病毒等方法获得了数据库的密码后便可直接通过因特网连接数据库服务器,进行破坏。
提高因特网上数据库服务器安全的比较实用的方法就是修改SQLServer的连接端口。
图5.1应用程序服务器直连数据库服务器 使用SQLServer配置管理工具可以修改TCP/IP协议中使用的端口,将端口改为比较陌生的端口,例如8412,或者修改为其他服务的端口例如443(主要是用于HTTPS服务)都可以误导入侵者,提高系统的安全性。

3.限制对SQLServer的网络访问仅仅是对默认端口的修改并不能保证数据库的安全,在黑客得知某端口对应的是数据库服务后仍然可以通过各种手段对数据库资料进行窃取和破坏。
对于暴露在因特网上的服务器,都应该使用防火墙来限制网络的访问,提高系统的安全。
实际上不仅仅是针对因特网,即使是局域网也有必要使用防火墙来提高系统的安全性。
如图5.2所示为一般大中型企业的服务器网络架构,在企业应用中充斥着各种应用服务器,各种服务器上运行着不同的服务,虽然大部分服务器是统一存放在一个机房中,但是在网络上它们之间是互不相连的。
所有的服务器都是通过防火墙再与其他系统或用户进行交互。
在防火墙上便可以配置服务器之间的网络访问策略。
通过使用防火墙限制对SQLServer的网络访问可以很大限度地提高数据库的安全性。
例如在图5.2中的网络架构中,如果数据库只用于网站应用,那么在防火墙上便可以设定只有Web服务器能够访问数据库服务器。
这样即使黑客知道了数据库服务器的地址,知道了开放的端口,哪怕知道了数据库的密码也无法通过网络非法访问数据库服务器。
服务器之间互不相连可以防止一台服务器被攻陷后,黑客以该服务器为肉鸡(黑客用语,即当做跳板的机器)轻易攻陷其他服务器。
例如黑客通过某系统漏洞攻陷了电子邮件服务器,但是由于防火墙限制了电子邮件服务器对数据库服务器的访问,所以数据库服务器仍然是安全的。

4.备份和还原策略在大中型企业应用中,数据库文件通常保存在SAN或磁盘阵列上,这样使数据库文件 ·149· 第2篇数据库安全 丢失或损坏的几率大大下降,但是为了减少人为误操作或恶意破坏造成的损失,日常对数据库的备份必不可少。
图5.2一般大中企业服务器网络架构 对数据库应该尽早而且经常备份。
如果数据库每天备份,那么即使发生意外,损失顶多是一天的数据;而如果数据库是每周备份一次,则有可能会损失一周的数据。
对数据库备份并不是将数据库备份到相同的磁盘上并忘记它。
数据库备份应该存放在一个独立的位置(最好是远离现场),以确保其安全,要不然一旦存储发生意外,数据库文件和备份就一同被损坏了。
在大型企业中一般采用磁带机进行备份并将备份的磁带专门存储在一个安全的地方。
除了物理上和网络上的安全外,操作系统安全性也至关重要。
及时更新操作系统ServicePack和升级包含重要的安全性增强功能。
通过数据库应用程序对所有更新和升级进行测试后,再将它们应用到操作系统。
减少外围应用是一项安全措施,它涉及停止或禁用未使用的组件。
减少外围应用后,对系统带来潜在攻击的途径也会减少,从而有助于提高安全性。
限制SQLServer外围应用的关键在于通过仅向服务和用户授予适当的权限来运行具有“最小权限”的所需服务。
·150· 第5章SQLServer2012安全 5.1.2主体与数据库对象安全性 主体是指获得了SQLServer访问权限的个体、组和进程。
“安全对象”是服务器、数据库和数据库包含的对象。
每个安全对象都拥有一组权限,可对这些权限进行配置以减少SQLServer外围应用。
安全对象是SQLServer数据库引擎授权系统控制对其进行访问的资源。
通过创建可以为自己设置安全性名为“范围”的嵌套层次结构,可以将某些安全对象包含在其他安全对象中。
安全对象范围有服务器、数据库和架构,分别包括以下数据库对象。
服务器安全对象包括:端点、登录账户和数据库。
数据库安全对象包括:用户、角色、应用程序角色、程序集、消息类型、路由、 服务、远程服务绑定、全文目录、证书、非对称密钥、对称密钥、约定和架构。
架构安全对象包括:类型、XML架构集合和对象。
这里的对象包括聚合、约束、 函数、过程、队列、统计信息、同义词、表和视图。
SQLServer支持安全套接字层(SSL),并且与协议安全(IPSec)兼容。
启用SSL加密,将增强在SQLServer实例与应用程序之间通过网络传输的数据安全性。
但是,启用加密的确会降低性能。
SQLServer与客户端应用程序之间的所有通信流量都使用SSL加密时,还需要进行以下额外处理:由于加密机制的需要,连接时需要进行额外的网络往返。
从应用程序发送到SQLServer实例的数据包必须由客户端网络库加密并由服务器 端网络库解密。
从SQLServer实例发送到应用程序的数据包必须由服务器端网络库加密并由客户 端网络库解密。
除了SQLServer连接加密以外,SQLServer还提供了大量函数支持加密、解密、数字签名,以及数字签名验证。
加密并不解决访问控制问题。
不过,它可以通过限制数据丢失来增强安全性,即使在访问控制失效的罕见情况下也能如此。
例如,在数据库主机配置有误且恶意用户获取了包含敏感数据(如信用卡号)数据库的情况下,如果被盗信息已加密,则此信息将毫无用处。
在SQLServer加密中,证书是在两个服务器之间共享的软件“密钥”,使用证书进行加密后,可以通过严格的身份验证实现安全通信。
可以在SQLServer中创建和使用证书,以增强对象和连接的安全性。
5.1.3应用程序安全性 实际与用户交流的是应用程序客户端,所以SQLServer安全性包括编写安全客户端应用程序。
不安全的客户端应用程序容易出现SQL注入漏洞或暴露数据库链接信息。
在最简单的情况下,SQLServer客户端可与SQLServer实例运行在同一台计算机上。
对于一般的企业应用来说,通常一个客户端可能会通过网络连接多个服务器,而一个数据库服务器也可能连接着多个客户端。
默认的客户端配置可以满足大多数情况。
SQLServer客户端可以使用多种方式来连接数据库。
一般是SQLServerNativeClient ·151· 第2篇数据库安全 OLEDB访问接口连接到SQLServer实例。
使用ADO.NET编程连接SQLServer,以及sqlcmd命令提示工具和数据库管理工具SQLServerManagementStudio,都是OLEDB应用程序的例子。
另外,随SQLServer旧版本安装的客户端实用工具则使用SQLServerNativeClientODBC驱动程序连接到SQLServer。
除了OLEDB和ODBC方式外,有些程序是使用DB-Library的客户端连接数据库。
不过SQLServer对使用DB-Library的客户端支持,仅限于MicrosoftSQLServer7.0功能。
无论客户端使用哪种方式连接SQLServer,都应该根据实际项目要求对客户端进行管理。
对客户端管理的范围可以小到输入服务器名称,大到生成自定义配置项库,以便满足各种各样的多服务器环境。
5.2账号管理 SQLServer2012账号管理分为登录验证、权限、角色和架构等。
通过对账号的管理可以有效地提高数据库系统的安全,降低维护的成本。
本节将对SQLServer账号管理进行讲解。
5.2.1安全验证方式 在数据库的使用中,经常看到一个数据库中的超级管理员用户(sa)被整个部门甚至整个公司的每一个员工使用,而整个数据库中可能就只有这一个账户,也就是说每个人都知道超级管理员的密码。
这样是非常不安全的,因为并不知道到底是谁登录了系统。
数据库的超级管理员应该限制在几个人(如DBA)之内,超级管理员具有完全的访问权限。
对于不同的部门或者项目组的用户,使用不同的用户,而且应该遵循权限最小化的原则,即只提供相应数据库中需要使用的权限,其他权限都不提供。
最理想的情况是每个账号只对应一个人,而且只有他本人知道该账号的密码,这样就可以知道谁登录了数据库,做了什么操作了。
SQLServer2012提供了两种身份认证方式:Windows身份认证和SQLServer身份认证。
Windows身份认证是基于Windows操作系统自身的身份认证方式进行的安全验证。
Windows身份认证中使用的用户包括本地用户和活动目录(AD)上的域用户。
对于使用AD进行管理的企业和开发团队来说,使用Windows身份认证是一种比较方便有效的管理办法。
SQLServer并不管理域用户的密码,域用户统一由AD服务器负责管理。
可以在SQLServer中为每个域用户配置相应的权限,而使用了域用户的客户端在登录数据库时也跟Windows本地登录一样,不用再输用户名密码即可登录。
SQLServer身份认证是由SQLServer系统自身维护的一套用户系统。
在没有域的情况下就需要使用SQLServer身份认证进行远程登录。
默认情况下,如果安装SQLServer时选择了混合身份认证选项,则sa账户是系统默认的全局超级管理员。
使用SQLServer身份认证具有以下优点:用户不一定是域账户也可以远程访问系统。
·152· 第5章SQLServer2012安全 很容易用程序控制用户信息。
比基于Windows认证的安全性更容易维护。
5.2.2密码策略 SQLServer自身并不设置密码策略,SQLServer通过Windows操作系统来实施密码策略。
Windows的密码策略包括:密码复杂性、密码长度最小值、密码最长使用期限、密码最短使用期限、强制密码历史和可还原的密码加密存储密码。
要查看当前Windows的密码策略或修改密码策略,可以使用Windows自带的管理工具“本地安全策略”,在开始按钮下的管理工具中可以找到该选项。
打开“本地安全策略”对话框后,展开左侧“安全设置”选项下的“账户策略”选项,选中“密码策略”便可看到当前系统的密码策略,如图5.3所示。
图5.3“本地安全策略”对话框 如果启用“密码必须符合复杂性要求”策略,则密码必须符合以下最低要求:不得明显包含用户账户名或用户全名的一部分。
长度至少为6个字符。
包含来自以下4个类别中的3个字符:英文大写字母(从A~Z)、英文小写字母 (从a~z)、10个基本数字(从0~9)和非字母字符(例如,!
、$、#、%)。
人们一般习惯于使用个人的数字(生日、手机号和证件号等)、名字、易记数字(123456或888888等)和其他个人信息作为密码,如果没有启用密码策略,这些密码将很容易通过字典穷举的方式被破解。
而启用密码策略后这些低强度的密码将不能作为合法密码使用,为了便于记忆仍然可以使用这些常见的密码进行组合变形后使用,例如P@ssw0rd!
、Study(a)、HeHuan0915!
等易记却不易被破解。
密码长度最小值可用于进一步加强密码的强度,在密码复杂性中要求密码至少有6个字符,这里可以设置为10个或更多来进一步提高密码强度。
密码最长使用期限用于设置密码的有效期。
在有效期之后原密码将无效,用户必须更改为新的密码才能登录系统。
设置密码有效期是为了防止密码被别人长期使用或密码泄露。
·153· 第2篇数据库安全 例如由于设置的密码比较复杂,不容易记住,所以计算机的管理员A将密码写在了笔记本上,几个月后该笔记本被B获得,如果设置了密码有效期,A在这之前修改了密码,则B得到的只是几个月前的密码,而不是系统的密码,从而保证了系统的安全。
说明:密码最短使用期限用于设置两次修改密码的时间间隔,为0表示可以随时修改 密码。
强制密码历史是强制修改后的密码与前几次密码必须不相同,这是为了防止用户在密码过期后为了一时方便将新密码设置为和前几次的密码中的一个相同。
若需要强制密码历史笔者建议至少跟踪老口令10次,不能让用户在这一时期内使用相同的密码两次。
在设置了Windows的密码策略后,在SQLServer中建立登录用户时可以选择强制实施密码策略。
关于如何创建用户和如何应用密码策略将在5.3节进行讲解。
5.2.3高级安全性 guest账户提供了具有默认访问权限的一种方法。
当guest账户被激活时,登录用户获得了没有直接给他们提供访问权限的数据库的guest级访问权限。
同时外面的用户可以使用guest账户登录得到访问权限。
在SQLServer中有必要对guest账户进行处理,删除该账户可能访问的机会。
除了guest账户外sa账户是SQLServer中最敏感的账户了,有SQLServer常识的人都知道,sa账户是超级管理员账户,在知道了用户名的情况下只需要破解密码比同时破解用户名和密码简单得多。
出于安全的考虑,最好能建立其他的登录用户来代替sa,而将sa禁用。
如果是使用Windows账户登录,则系统默认是禁用了sa的。
另外,在SQLServer中有一个非常特殊的存储过程xp_cmdshell,运行该存储过程需要具有对应的权限。
该存储过程用于生成Windows命令shell,并以字符串的形式传递以便执行。
该存储过程常被用于提升权限等非法操作,在SQLServer2000中该存储过程是启用的,但是在SQLServer2012中默认禁用了该存储过程。
读者若想知道当前系统是否启用了xp_cmdshell,只需要运行以下命令即可。
EXECmaster..xp_cmdshell'dir' 如果未启用该存储过程,系统将会抛出异常: SQLServer阻止了对组件'xp_cmdshell'的过程'sys.xp_cmdshell'的访问,因为此组件已作为此服务器安全配置的一部分而被关闭…… 如果读者需要启用xp_cmdshell,可以使用sp_configure来启用。
具体启用脚本如代码5.1所示。
代码5.1启用xp_cmdshellEXECsp_configure'showadvancedoptions',1--修改服务器配置GORECONFIGUREGOEXECsp_configure'xp_cmdshell',
1 ·154· 第5章SQLServer2012安全GORECONFIGUREGO 在SQLServer2005版中除了使用SQL命令外也可以通过SQLServer自带的SQLServer外围应用配置器来启用或禁用xp_cmdshell,但是在2012版中该工具被取消。
启用SQLServer外围应用配置器后,单击“功能的外围应用配置器”链接,系统将打开功能的外围应用配置器窗口,在按实例查看选项卡中可以找到xp_cmdshell,单击xp_cmdshell,右侧将出现“启用xp_cmdshell”的复选框,如图5.4所示。
若要启用则选中该复选框,反之则不选中,单击“确定”按钮即可完成对xp_cmdshell的配置。
图5.4配置xp_cmdshell 5.3登录名管理 登录名是用户登录SQLServer的重要标识,若要登录到SQLServer数据库系统,主体必须具有有效的SQLServer登录名。
在身份验证过程中会使用此登录名,以验证是否允许主体连接到该SQLServer实例。
目前比较常用的管理SQLServer登录用户的方式有两种:使用T-SQL和使用SSMS可视化界面。
本节将使用这两种方式讲解登录名的管理。
5.3.1使用T-SQL创建登录名 SQLServer提供了CREATELOGIN命令用于创建登录名。
该命令的语法格式如代码5.2所示。
代码5.2CREATELOGIN的语法CREATELOGINloginName{WITH|FROM}::= PASSWORD={'password'|hashed_passwordHASHED}[MUST_CHANGE][,[,...]]::=SID=sid|DEFAULT_DATABASE=database ·155· 第2篇数据库安全 |DEFAULT_LANGUAGE=language|CHECK_EXPIRATION={ON|OFF}|CHECK_POLICY={ON|OFF}|CREDENTIAL=credential_name::=WINDOWS[WITH[,...]]|CERTIFICATEcertname|ASYMMETRICKEYasym_key_name::=DEFAULT_DATABASE=database|DEFAULT_LANGUAGE=language 其中比较重要的几个参数说明如下。
loginName:指定创建的登录名。
有4种类型的登录名:SQLServer登录名、Windows 登录名、证书映射登录名和非对称密钥映射登录名。
如果从Windows域账户映射loginName,则loginName必须用方括号([])括起来。
PASSWORD='password':仅适用于SQLServer登录名,指定正在创建的登录名的密码。
MUST_CHANGE:仅适用于SQLServer登录名。
如果包括此选项,则SQLServer将在首次使用新登录名时提示用户输入新密码。
DEFAULT_DATABASE=database:指定将指派给登录名的默认数据库。
如果未包括此选项,则默认数据库将设置为master。
DEFAULT_LANGUAGE=language:指定将指派给登录名的默认语言。
如果未包括此选项,则默认语言将设置为服务器的当前默认语言。
即使将来服务器的默认语言发生更改,登录名的默认语言也仍保持不变。
CHECK_EXPIRATION={ON|OFF}:仅适用于SQLServer登录名,指定是否对此登录账户强制实施密码过期策略。
默认值为OFF。
CHECK_POLICY={ON|OFF}:仅适用于SQLServer登录名。
指定应对此登录名强制实施运行SQLServer计算机的Windows密码策略。
默认值为ON。
注意:只有在WindowsServer2003及更高版本上才能执行CHECK_EXPIRATION和 CHECK_POLICY。
例如要创建一个登录名testuser1,创建时的密码为123456,由于该密码可能不符合Windows的密码策略,所以在该账户上不使用Windows密码策略。
创建登录名的SQL脚本如代码5.3所示。
代码5.3使用CREATELOGIN创建登录名 CREATELOGINtestuser1WITHPASSWORD='password1',CHECK_POLICY=OFF--不启用Windows密码策略 如果要将当前Windows账户中的用户SQLAdmin添加到SQLServer登录用户中,则对应的SQL脚本为: CREATELOGIN[MS-ZY\SQLAdmin]FROMWINDOWS--基于Windows认证 ·156· 第5章SQLServer2012安全 除了CREATELOGIN命令外,SQLServer还提供了sp_addlogin系统存储过程用于添加登录名,不过不推荐使用这种方式,SQLServer可能在以后的版本中删除该存储过程。
其使用语法如代码5.4所示。
代码5.4sp_addlogin的语法sp_addlogin[@loginame=]'login' [,[@passwd=]'password'][,[@defdb=]'database'][,[@deflanguage=]'language'][,[@sid=]sid][,[@t=]'encryption_option'] 该存储过程中只有@loginame参数是必须的,其他参数都提供了默认值,但是一般情况下需要指定@loginname和@passwd这两个参数。
每个参数的含义如下所述。
[@loginame=]'login':登录的名称。
login的数据类型为sysname,无默认值。
[@passwd=]'password':登录的密码。
password的数据类型为sysname,默认值为 NULL。
[@defdb=]'database':登录的默认数据库(在登录后登录首先连接到该数据库)。
database的数据类型为sysname,默认值为master。
[@deflanguage=]'language':登录的默认语言。
language的数据类型为sysname,默 认值为NULL。
如果未指定language,则新登录的默认language将设置为服务器的当前默认语言。
[@sid=]'sid':安全标识号(SID)。
sid的数据类型为varbinary(16),默认值为NULL。
如果sid为NULL,则系统将为新登录生成SID。
不管是否使用varbinary数据类型,NULL以外的值的长度都必须正好是16个字节,并且一定不能已经存在。
[@t=]'encryption_option':指定是以明文形式,还是以明文密码的哈希运算结果来传递密码。
如果传入明文密码,将对它进行哈希运算,哈希值将存储起来。
说明:如果没有指定@passwd参数,那么建立的用户将是空密码,这是很危险的,最好 在建立用户时就将密码指定,而且最好使用强密码。
例如要建立一个用户testuser1,该用户的密码是password1,则只需要运行以下脚本。
EXECsp_addlogintestuser1,'password1' 说明:sp_addlogin的实质还是通过调用CREATELOGIN命令来创建登录名,该存储过 程只是对CREATELOGIN命令的简化封装,读者可以运行sp_helptextsp_addlogin命令来查看该存储过程的定义。
5.3.2使用SSMS创建登录名 在SSMS中创建登录名的操作步骤如下所述。

(1)使用对服务器拥有ALTERANYLOGIN或ALTERLOGIN权限的用户(如sa) ·157· 第2篇数据库安全 登录进SQLServer。

(2)在对象资源管理器中展开“安全性”节点下的“登录名”节点并右击,在弹出的 快捷菜单中选择“新建登录名”选项,系统将弹出“登录名-新建”对话框,如图5.5所示。
图5.5“登录名-新建”对话框
(3)如果要创建的登录名是Windows用户,则单击该对话框右侧的“搜索”按钮查找并选择Windows用户;如果是创建SQLServer登录名,则直接输入登录名(例如创建testuser2)并选中“SQLServer身份认证”单选按钮。

(4)对于SQLServer身份认证,需要输入密码和确认密码,两次输入的密码必须相同。

(5)对于SQLServer身份认证,若要实施密码策略,则选中“强制实施密码策略”复选框。
在没有选中“强制密码过期”复选框的情况下是无法选中“用户在下次登录时必须更改密码”复选框的,如图5.6所示。

(6)选择默认数据库和默认语言,一般情况下就使用默认设置。

(7)单击“确定”按钮,如果启用了密码策略并且当前密码符合Windows的密码策略则创建用户成功。
创建后的用户将出现在对象资源管理器中,如图5.7所示。
·158· 图5.6密码策略选项 图5.7在对象资源管理器中查看登录名 第5章SQLServer2012安全 5.3.3使用T-SQL修改登录名 在创建好用户后,如希望对用户的密码进行更改,则需要使用ALTERLOGIN命令。
该命令的语法如代码5.5所示。
代码5.5ALTERLOGIN的语法 ALTERLOGINlogin_name{|WITH[,...]|} ::=ENABLE|DISABLE ::=PASSWORD='password'|hashed_passwordHASHED[OLD_PASSWORD='oldpassword'|[]]|DEFAULT_DATABASE=database|DEFAULT_LANGUAGE=language|NAME=login_name|CHECK_POLICY={ON|OFF}|CHECK_EXPIRATION={ON|OFF}|CREDENTIAL=credential_name|NOCREDENTIAL ::=MUST_CHANGE|UNLOCK ::=ADDCREDENTIALcredential_name|DROPCREDENTIALcredential_name 其中重要的参数介绍如下。
login_name:指定正在更改的SQLServer登录的名称。
ENABLE|DISABLE:启用或禁用此登录。
PASSWORD='password':仅适用于SQLServer登录账户。
指定正在更改的登录 的密码。
密码是区分大小写的。
OLD_PASSWORD='oldpassword':仅适用于SQLServer登录账户,要指定当前密 码。
密码是区分大小写的。
MUST_CHANGE:仅适用于SQLServer登录账户。
如果包括此选项,则SQLServer 将在首次使用已更改的登录时提示输入更新的密码。
DEFAULT_DATABASE=database:指定登录后的默认数据库。
DEFAULT_LANGUAGE=language:指定登录后的默认语言。
NAME=login_name:正在重命名的登录的新名称。
如果是Windows登录,则与 ·159· 第2篇数据库安全 新名称对应的Windows主体的SID,必须匹配与SQLServer中登录相关联的SID。
SQLServer登录的新名称不能包含反斜杠字符(\)。
CHECK_EXPIRATION={ON|OFF}:仅适用于SQLServer登录账户。
指定是否对此登录账户强制实施密码过期策略。
默认值为OFF。
CHECK_POLICY={ON|OFF}:仅适用于SQLServer登录账户。
指定应对此登录名强制实施运行SQLServer的计算机的Windows密码策略。
默认值为ON。
使用ALTERLOGIN需要具有ALTERANYLOGIN的权限。
如果正在更改的登录名是sysadmin固定服务器角色的成员,或CONTROLSERVER权限的被授权者,则进行以下更改时还需要CONTROLSERVER权限:在不提供旧密码的情况下重置密码。
启用MUST_CHANGE、CHECK_POLICY或CHECK_EXPIRATION。
更改登录名。
启用或禁用登录。
将登录映射到其他凭据。
主体可更改用于自身登录的密码、默认语言,以及默认数据库。
例如,使用sa账户来修改前面创建的用户testuser1的密码为abcdefg,则使用ALTERLOGIN的脚本为: ALTERLOGINtestuser1WITHPASSWORD='abcdefg' 以上代码的执行需要当前用户具有ALTERANYLOGIN的权限,如果是使用刚创建的用户testuser1登录并执行以上SQL脚本,系统将抛出异常: 消息15151,级别16,状态
1,第1行无法对登录名'testuser1'执行更改,因为它不存在,或者您没有所需的权限。
在没有ALTERANYLOGIN权限的情况下,用户必须使用OLD_PASSWORD指定原密码,在原密码正确的情况下才能修改当前用户的密码。
例如使用testuser1连接数据库,该用户的原密码是password1,如果将该用户的密码修改为abcdefg,则对应的SQL脚本如代码5.6所示。
代码5.6ALTERLOGIN修改密码 ALTERLOGINtestuser1WITHPASSWORD='abcdefg'OLD_PASSWORD='password1'--必须指定原密码 若希望修改登录名testuser1为testuser11或者禁用某登录名也是使用ALTERLOGIN命令。
具体SQL脚本如代码5.7所示。
代码5.7修改、禁用登录名 ALTERLOGINtestuser1--修改登录名WITHNAME=testuser11GO ·160· 第5章SQLServer2012安全ALTERLOGINtestuser11DISABLE--禁用登录名 同创建登录名中可以使用sp_addlogin一样,系统还提供了sp_password存储过程用于修改密码,不过这种修改密码的方法已经过时,在将来的SQLServer系统中将会删除该功能。
sp_password的语法如代码5.8所示。
代码5.8sp_password的语法sp_password[[@old=]'old_password',] {[@new=]'new_password'}[,[@loginame=]'login'] 其中的@loginame如果未指定,则表示修改当前用户的密码。
该存储过程使用所需权限与ALTERLOGIN相同,若具有ALTERANYLOGIN的权限可以不给出原密码。
说明:sp_password的实质还是调用了ALTERLOGIN,该存储过程实际上就是对 ALTERLOGIN命令修改密码功能的封装,使用sp_helptextsp_password命令可以看到该存储过程的定义,读者若有兴趣可以运行该命令查看其内容。
5.3.4使用SSMS修改登录名 使用SSMS修改前面创建的登录名testuser2,其操作步骤如下所述。

(1)使用具有ALTERANYLOGIN权限的账户登录系统。

(2)在对象资源管理器中展开“安全性”节点下的“登录名”节点。
在“登录名”节点下找到前面创建的testuser2登录名。

(3)右击testuser2登录名,在弹出的快捷菜单中选择“属性”选项,或者直接双击testuser2登录名,系统将弹出“登录属性”对话框,如图5.8所示。
图5.8“登录属性”对话框
(4)若要重新设置密码,在密码文本框和确认密码文本框中可以输入密码。
·161· 第2篇数据库安全 注意:“登录属性”对话框中,密码文本框里*的个数并不是密码的长度,不论原密码 有几位,这里都是用十几个*来表示。

(5)在“强制实施密码策略”文本框中可以修改该用户的密码策略和强制密码过期,但是无法选中“用户在下次登录时必须更改密码”复选框。

(6)最下面可以更改默认数据库和默认语言。

(7)若要修改登录名的状态,禁用该登录名或重新启用该登录名,需要单击左侧的“状态”链接,系统进入状态选项卡,如图5.9所示。
图5.9登录属性的状态选项卡
(8)在状态窗口可以选择“已启用”单选按钮或“禁用”单选按钮来启用或禁用登录名。

(9)单击“确定”按钮完成对登录名的修改。
如果需要对登录名进行重命名,只需要选中登录名使用快捷键F2或者右击某登录名, 在弹出的快捷菜单中选中“重命名”选项,便可重新命名登录名。
5.3.5删除登录名 使用T-SQL删除登录非常简单,SQLServer提供了DROPLOGIN命令用于删除登录名,其语法为: DROPLOGINlogin_name 其不能删除正在登录的登录名,要删除登录名需要对服务器具有ALTERANYLOGIN ·162· 第5章SQLServer2012安全 权限。
例如要删除前面创建并重命名的登录名testuser11,则运行脚本: DROPLOGINtestuser11 使用SSMS删除登录名的方式与删除其他数据库对象(如表、存储过程和视图等)一样。
在对象资源管理器中选中要删除的登录名,使用快捷键Delete,系统将弹出删除对象窗口,单击“确定”按钮即可删除登录名。
5.4用户管理 在5.3节创建的登录名提供了登录权限,在登录后如果要让该用户具有数据库的访问权,那么要给该用户授予数据库访问权。
授予数据库访问权是通过把一个用户(User)添加到需要访问的数据库的Users成员中实现的。
本节将主要讲解对用户的管理操作。
5.4.1使用T-SQL创建用户 在5.3节创建登录名时,如果使用非系统数据库,例如AdventureWorks2012作为默认数据库,则使用该登录名将无法登录SQLServer,SQLServer将抛出异常“无法打开用户默认数据库,登录失败”,这是由于在AdventureWorks2012数据库中没有该登录名对应的用户。
只有在登录名对应了数据库中的用户后该登录名才可以访问对应的数据库。
在T-SQL下通过CREATEUSER命令创建用户,CREATEUSER的语法如代码5.9所示。
代码5.9CREATEUSER的语法 CREATEUSERuser_name [{{FOR|FROM} { LOGINlogin_name |CERTIFICATEcert_name |ASYMMETRICKEYasym_key_name } |WITHOUTLOGIN ][WITHDEFAULT_SCHEMA=schema_name] 运行CREATEUSER命令需要对数据库具有ALTERANYUSER权限。
如果已忽略FORLOGIN,则新的数据库用户将被映射到同名的SQLServer登录名。
如果未定义DEFAULT_SCHEMA,则数据库用户将使用dbo作为默认架构。
其中,user_name指定在此数据库中用于识别该用户的名称。
LOGINlogin_name指定要创建数据库用户的SQLServer登录名。
login_name必须是服务器中有效的登录名。
当此SQLServer登录名进入数据库时,它将获取正在创建的数据库用户的名称和ID。
注意:不能使用CREATEUSER创建guest用户,因为每个数据库中均已存在guest用户。
例如,要创建登录名testuser1并在AdventureWorks2012数据库上创建同名的用户,则对应的SQL脚本如代码5.10所示。
·163· 第2篇数据库安全 代码5.10创建登录名和同名用户 CREATELOGINtestuser1--创建登录名WITHPASSWORD='abcdefg';--指定密码 GOUSEAdventureWorks2012;CREATEUSERtestuser1;--创建用户GO 另外,若要创建的用户与登录名不相同,则必须要指定用户对应的登录名。
例如创建登录名testuser2,在数据库AdventureWorks2012中创建用户test2的SQL脚本如代码5.11所示。
代码5.11创建不同的登录名和用户 CREATELOGINtestuser2WITHPASSWORD='abcdefg'; GOUSEAdventureWorks2012;CREATEUSERtest2FORLOGINtestuser2--必须指定对应的登录名GO 注意:登录名和具体数据库中的用户是一对一的关系,也就是说,一个登录名在一个数 据库中最多只能对应一个用户,而一个用户也只对应一个登录名。
但是对应整个SQLServer实例来说,登录名与用户是一对多的关系,因为一个登录名可以在每一个数据库中创建不同的用户。
在未创建用户时运行USEAdventureWorks2012命令系统将抛出异常: 服务器主体"testuser1"无法在当前安全上下文下访问数据库"AdventureWorks2012"。
在创建了用户与登录名的对应后,用户就可以正确运行USEAdventureWorks2012了。
技巧:若要查看当前连接在数据库中对应的用户,可以使用CURRENT_USER()函数或 者使用USER_NAME()函数,运行SELECTCURRENT_USER即可。
5.4.2使用SSMS创建用户 在SSMS的可视化界面下创建用户的主要操作如下所述。

(1)使用对AdventureWorks2012数据库具有ALTERANYUSER权限的用户,如sa登录进SQLServer。

(2)在对象资源管理器中展开AdventureWorks2012数据库“安全性”节点“用户”下的节点。

(3)右击“用户”节点,在弹出的快捷菜单中选择“新建用户”选项,系统将弹出“数据库用户-新建”对话框,如图5.10所示。

(4)在“用户名”文本框中输入需要新建的用户名。
·164· 第5章SQLServer2012安全 图5.10“数据库用户-新建”对话框
(5)在“登录名”文本框中输入登录名,也可以使用“登录名”文本框右侧的按钮来帮助选择登录名。

(6)“默认架构”文本框可以不填,系统将自动默认为dbo。

(7)此用户拥有的架构和数据库角色成员身份两个选项暂不选择,这两个属性在接下来的章节中将进行讲解。

(8)单击“确定”按钮,用户就建立完成。
建立的用户将在对象资源管理器中展示,如图5.11所示。
图5.11在对象资源管理器中查看用户 ·165· 第2篇数据库安全 5.4.3修改用户 修改用户使用ALTERUSER命令。
ALTERUSER的语法如代码5.12所示。
代码5.12ALTERUSER的语法ALTERUSER WITH ALTERUSER的功能很简单,就是用于重命名数据库用户或更改它的默认架构。
例如,要修改前面创建的用户testuser1为test1而默认的架构不变,则对应的SQL脚本如代码5.13所示。
代码5.13修改用户USEAdventureWorks2012;GOALTERUSERtestuser1--修改用户的名字 WITHNAME=test1GO 使用SSMS修改用户与修改登录名类似,具体操作如下所述。

(1)使用对数据库具有ALTERANYUSER权限的用户登录。

(2)在对象资源管理器中双击需要修改的用户,系统将弹出“数据库用户”对话框,如图5.12所示。
图5.12“数据库用户”对话框
(3)在该对话框中可以修改用户的默认架构,不能修改用户名。
·166· 第5章SQLServer2012安全
(4)修改默认架构后单击“确定”按钮,默认架构修改完成。
注意:要修改用户名只能通过T-SQL进行修改,SSMS不提供修改用户名的操作。
5.4.4删除用户 若要删除用户,使用DROPUSER命令即可。
例如要删除前面创建的用户test1,对应的脚本是: DROPUSERtest1 在SSMS下删除用户的操作也和删除登录名相同。
在对象资源管理器中找到需要删除的用户,然后使用快捷键Delete,系统将弹出确认对话框,单击“确定”按钮即可完成对用户的删除。
5.5架构管理 从SQLServer2005起,架构行为已更改,架构不再等效于数据库用户;现在,每个架构都是独立于创建该架构的数据库用户而存在,架构与数据库用户是不同的命名空间。
也就是说,架构只是对象的容器。
架构与用户的分离方便了数据库的管理。
本节将主要讲解架构的基础知识。
5.5.1架构简介 架构(schema)是指包含表、视图、存储过程等数据库对象的容器。
从包含关系上来讲,架构位于数据库内部,而数据库位于服务器内部。
这些实体就像嵌套框放置在一起。
服务器实例是最外面的框,而架构是最里面的框。
XML架构集合、表、视图、过程、函数、聚合函数、约束、同义词、队列和统计信息等数据库对象都是必须位于架构内部的安全对象。
特定架构中的每个安全对象都必须有唯一的名称,而不同的架构下可以有相同的数据库对象名称,例如,在一个数据库中可以同时存在dbo.Department表和mis.Department表。
架构中安全对象的完全指定名称包括此安全对象所在的架构名称。
因此,架构也是命名空间。
在默认情况下,系统的默认架构是dbo。
如果是访问默认架构中的对象则可以忽略架构名称,否则在访问表、视图等对象时需要指定架构名称,例如mis.Customer和eip.vwDepartment等。
注意:在SQLServer2000和早期版本中,数据库可以包含一个名为“架构”的实体, 但此实体实际上是数据库用户。
在SQLServer2005、SQLServer2008和SQLServer2012中,架构既是一个容器,又是一个命名空间。
从SQLServer2005起将所有权与架构分离具有重要的意义: ·167· 第2篇数据库安全 架构的所有权和架构范围内的安全对象可以转移。
对象可以在架构之间移动。
单个架构可以包含由多个数据库用户拥有的对象。
架构和用户之间是多对多的关 系,一个用户可以拥有多个架构,一个架构也可以分给多个用户。
多个数据库用户可以共享单个默认架构。
与早期版本相比,对架构及架构中包含的安全对象权限的管理更加精细。
架构可以由任何数据库主体拥有,其中包括角色和应用程序角色。
可以删除数据库用户而不删除相应架构中的对象。
删除用户并不会造成对架构和 架构中对象的影响。
5.5.2使用T-SQL创建架构 在T-SQL中创建架构需要使用CREATESCHEMA命令,要运行该命令需要对数据库具有CREATESCHEMA权限。
CREATESCHEMA的语法结构如代码5.14所示。
代码5.14CREATESCHEMA的语法 CREATESCHEMAschema_name_clause[[...n]]::= {schema_name |AUTHORIZATIONowner_name|schema_nameAUTHORIZATIONowner_name}::={ table_definition|view_definition|grant_statementrevoke_statement|deny_statement} 其中的参数说明如下所述。
schema_name:在数据库内标识架构的名称。
AUTHORIZATIONowner_name:指定将拥有架构的数据库级主体的名称。
此主体 还可以拥有其他架构,并且可以不使用当前架构作为其默认架构。
table_definition:指定在架构内创建表的CREATETABLE语句。
执行此语句的主 体必须对当前数据库具有CREATETABLE权限。
view_definition:指定在架构内创建视图的CREATEVIEW语句。
执行此语句的主 体必须对当前数据库具有CREATEVIEW权限。
grant_statement:指定可对除新架构外的任何安全对象授予权限的GRANT语句。
revoke_statement:指定可对除新架构外的任何安全对象撤销权限的REVOKE语句。
deny_statement:指定可对除新架构外的任何安全对象拒绝授予权限的DENY语句。
这里需要关注的是schema_name和owner_name。
新架构的拥有者可以是数据库用户、数据库角色或应用程序角色。
在架构内创建的对象由架构所有者拥有。
架构所包含对象的所有权可转让给任何数据库级别主体,但架构所有者始终保留对此架构内对象的 ·168· 第5章SQLServer2012安全 CONTROL权限。
例如,要在AdventureWorks2012数据库中创建一个架构t1,该架构的拥有者为前面创 建的用户test1。
对应的SQL脚本如代码5.15所示。
USEAdventureWorks2012;GOCREATESCHEMAt1 AUTHORIZATIONtest1 代码5.15创建架构--架构的拥有者为test1用户 注意:在一个数据库中用户和架构是一对多的关系,也就是说可以为一个用户创建多个 架构,但是一个架构只能指定一个拥有者。
如果在CREATESCHEMA中未指定拥有者,系统默认将dbo作为架构的拥有者。
5.5.3使用SSMS创建架构 使用SSMS创建架构的主要操作步骤如下所述。

(1)使用对数据库具有CREATESCHEMA权限的用户,例如sa登录系统。

(2)在对象资源管理器中展开AdventureWorks2012数据库的“安全性”节点下的“架构”节点。

(3)右击“架构”节点,在弹出的快捷菜单中选择“新建架构”选项,系统将弹出“架构-新建”对话框,如图5.13所示。
图5.13“架构-新建”对话框 ·169· 第2篇数据库安全
(4)在“架构名称”文本框中输入架构的名称。

(5)在“架构所有者”文本框中输入架构的所有者用户,或者单击“搜索”按钮,系统将弹出“搜索角色和用户”对话框,如图5.14所示。
图5.14“搜索角色和用户”对话框
(6)单击“浏览”按钮系统将弹出“查找对象”对话框,其中列出了数据库中所有的角色和用户,如图5.15所示。
图5.15“查找对象”对话框
(7)在其中选中架构的拥有者对象并单击“确定”按钮,最后在“架构-新建”对话框中单击“确定”按钮完成架构的创建工作。
5.5.4修改架构 若要修改架构需要使用ALTERSCHEMA命令,该命令的语法格式为: ALTERSCHEMAschema_nameTRANSFERsecurable_name 其中,schema_name用于指定当前数据库中的架构名称,安全对象将移入其中。
其数据类型不能为SYS或INFORMATION_SCHEMA。
securable_name为要移入架构中的原架 ·170· 第5章SQLServer2012安全 构中所包含的安全对象的名称。
ALTERSCHEMA仅可用于在同一数据库中的架构之间移动安全对象。
若要更改或删 除架构中的安全对象,可使用特定于该安全对象的ALTER或DROP语句。
例如在AdventureWorks2012中创建了表Student,该表所使用的架构是dbo,现在需要将该表的架构修改为t1,则对应的SQL脚本如代码5.16所示。
代码5.16使用ALTERSCHEMAUSE[AdventureWorks2012]GOCREATETABLEdbo.Student( sIDintIDENTITYPRIMARYKEY,sNamenvarchar(10)NOTNULL)GOALTERSCHEMAt1--修改架构TRANSFERdbo.Student 若要修改架构的所有者则需要使用ALTERAUTHORIZATION命令,该命令的语法格式如代码5.17所示。
代码5.17ALTERAUTHORIZATION的语法 ALTERAUTHORIZATIONON[::]entity_nameTO{SCHEMAOWNER|principal_name} ::={Object|Type|XMLSchemaCollection|FulltextCatalog|Schema|Assembly|Role|MessageType|Contract|Service|RemoteServiceBinding|Route|SymmetricKey|Endpoint|Certificate|Database} ALTERAUTHORIZATION用于更改安全对象的所有权。
其中“::”是更改其所有者实体的类。
Object是默认值,entity_name是实体名。
principal_name为将拥有实体的主体名称。
ALTERAUTHORIZATION可用于更改任何具有所有者实体的所有权。
数据库包含实体的所有权,可以传递给任何数据库级的主体。
服务器级实体的所有权只能传递给服务器级主体。
例如要将架构t1的所有者修改为test2用户,则对应的SQL脚本为: ALTERAUTHORIZATIONONSCHEMA::[t1]TO[test2] 5.5.5删除架构 若要删除某架构,则需要使用DROPSCHEMA命令,该命令的语法很简单: DROPSCHEMAschema_name ·171· 第2篇数据库安全 其中,schema_name为架构在数据库中所使用的名称,要删除的架构不能包含任何对象。
如果架构包含对象,则DROP语句将失败。
例如要删除前面用到的t1架构,则需要执行: DROPSCHEMAt1 执行该命令时系统将抛出异常: 无法对't1'执行dropschema,因为对象'PK__Student__DDDED94E405A880E'正引用它 这时需要将前面创建的Student表删除,或者使用ALTERSCHEMA命令将该表的架构修改为其他架构。
正确的删除t1架构的脚本如代码5.18所示。
代码5.18删除架构USE[AdventureWorks2012]GOALTERSCHEMAdbo TRANSFERt1.Student--修改Student表的架构为dboGODROPSCHEMAt1--删除t1架构 在SSMS下删除架构也是和其他对象的删除一样使用Delete键即可,此处不再详述。
5.6用户权限 简单地讲,用户权限就是规定用户可以做什么不可以做什么,在5.5节创建了登录用户后,本节将讲解用户权限的基础知识和权限的维护。
5.6.1权限简介 SQLServer2012数据库引擎管理着可以通过权限保护实体的分层集合。
这些实体称为“安全对象”。
在安全对象中,从服务器实例和数据库,到更细的级别上的表、视图等对象 都可以设置离散权限。
SQLServer通过验证主体是否已获得适当的权限,来控制主体对安全对象执行的操作。
在SQLServer用户权限可以分为3类: 登录权限。
访问特定数据库的权限。
在数据库特定对象上执行特定行为的权限。
前面讲到的登录名就是用于登录权限,用户就是访问特定数据库的权限,本节讲的就是数据库特定对象的权限。
如图5.16显示了SQLServer数据库引擎权限层次结构之间的关系。
在5.1节中已经介绍了按照容器从大到小来分,安全对象范围有服务器、数据库和架构。
各个容器中又有各自的安全对象,对于每一个容器和每一个安全对象都可以控制用户 ·172· 的访问权限。
第5章SQLServer2012安全 图5.16权限层次结构 通常使用T-SQL中的GRANT、DENY和REVOKE来操作权限,在设置权限时需要指定权限的名称,不同的权限使用不同的名称来表示。
SQLServer中对权限的名称有如下约定。
CONTROL:表示被授权者授予类似所有权的功能。
CONTROL权限可以被看做是一个权限的集合,被授权者实际上对安全对象具有所定义的所有权限。
SQLServer安全模型是分层的,所以对某个数据库集合授予CONTROL权限,意味着对该集合范围内的所有安全对象具有CONTROL权限。
例如,对某数据库架构具有CONTROL权限,隐含着对数据库架构下的所有表、视图、存储过程等,该架构下的所有对象具有的所有CONTROL权限。
对一个表具有CONTROL权限意味着对该表有查询、修改、删除等该对象上的所有权限。
ALTER:表示授予更改特定安全对象属性(所有权除外)的权限,ALTER权限相对于CONTROL权限范围要小一些。
如果对某个范围具有ALTER权限时,那么同时也具有了更改、创建或删除该范围内包含的任何安全对象的权限。
例如,对表的ALTER权限包括在该表中创建、更改和删除的权限,但是并不具有SELECT权限,而如果为表指定的是CONTROL权限时,则具有SELECT权限。
·173· 第2篇数据库安全 ALTERANY<服务器安全对象>:其中的服务器安全对象可以是任何前面说到的服务器安全对象。
授予创建、更改或删除服务器安全对象的各个实例的权限。
例如,ALTERANYLOGIN将授予创建、更改或删除实例中的任何登录名的权限。
ALTERANY<数据库安全对象>:其中的数据库安全对象可以是数据库级别的任何安全对象。
授予创建、更改或删除数据库安全对象的各个实例的权限。
例如,ALTERANYSCHEMA将授予创建、更改或删除数据库中的所有架构的权限。
TAKEOWNERSHIP:表示允许被授权者获取所授予的安全对象的所有权。
IMPERSONATE<登录名>:表示允许被授权者模拟该登录名。
IMPERSONATE<用户>:表示允许被授权者模拟该用户。
CREATE<服务器安全对象>:授予被授权者创建服务器安全对象的权限。
CREATE<数据库安全对象>:授予被授权者创建数据库安全对象的权限。
CREATE<包含在架构中的安全对象>:授予创建包含在架构中的安全对象的权限。
但是,若要在特定架构中创建安全对象,必须对该架构具有ALTER权限。
VIEWDEFINITION:表示允许被授权者访问元数据。
BACKUP和DUMP是同义词。
RESTORE和LOAD是同义词。
如表5.1列出了主要的权限类别,以及可应用这些权限的安全对象的种类。
权限SELECT 表5.1 VIEWCHANGETRACKINGUPDATE REFERENCES INSERTDELETEEXECUTE 权限适用的安全对象 适用于同义词表和列表值函数和列视图和列表架构同义词表和列视图和列标量函数和聚合函数ServiceBroker队列表和列表值函数和列视图和列同义词表和列视图和列同义词表和列视图和列过程标量函数和聚合函数同义词 ·174· 第5章SQLServer2012安全 权限RECEIVEVIEWDEFINITION ALTER TAKEOWNERSHIP CONTROL 适用于ServiceBroker队列过程ServiceBroker队列标量函数和聚合函数同义词表表值函数视图过程标量函数和聚合函数ServiceBroker队列表表值函数视图过程标量函数和聚合函数同义词表表值函数视图过程标量函数和聚合函数ServiceBroker队列同义词表表值函数视图 续表续表 5.6.2使用GRANT分配权限 GRANT用于给特定用户和角色授予了该对象指定的访问权限。
GRANT语句的语法如代码5.19所示。
代码5.19GRANT的语法 GRANT{ALL[PRIVILEGES]}|permission[(column[,...n])][,...n][ON[class::]securable]TOprincipal[,...n][WITHGRANTOPTION][ASprincipal] 其中,ALL关键字表示希望给该类型的对象授予所有可用的权限。
不推荐使用此选项,保留此选项仅用于向后兼容。
授予ALL参数相当于授予以下权限: 如果安全对象为数据库,则ALL表示BACKUPDATABASE、BACKUPLOG、CREATEDATABASE、CREATEDEFAULT、CREATEFUNCTION、CREATE ·175· 第2篇数据库安全 PROCEDURE、CREATERULE、CREATETABLE和CREATEVIEW等权限。
如果安全对象为标量函数,则ALL表示EXECUTE和REFERENCES。
如果安全对象为表值函数,则ALL表示DELETE、INSERT、REFERENCES、 SELECT和UPDATE。
如果安全对象是存储过程,则ALL表示EXECUTE。
如果安全对象为表,则ALL表示DELETE、INSERT、REFERENCES、SELECT 和UPDATE。
如果安全对象为视图,则ALL表示DELETE、INSERT、REFERENCES、SELECT 和UPDATE。
PRIVILEGES关键字是用于提供ANSI-92的兼容,并没有实际意义。
ON关键字显示了下一步出现的要授予权限的对象。
在对表进行授权时可以指定影响的列清单并说明许可权,如果不说明则默认为所有列。
TO语句指定了想给哪个登录ID或角色名授权。
WITHGRANTOPTION允许正在授权的用户将同样的权限授予其他用户。
AS关键字是用于处理登录属于多个角色的问题。
在前面已经建立了登录名和用户从而实现了登录权限和数据库访问权限,但是当使用建立的登录名连接数据库后将无法看到具有访问权限的数据库中的表、视图和存储过程等安全对象,下面就使用GRANT命令将特定权限授予该登录名。
在数据库中创建登录名testuser1,然后在AdventureWorks2012数据库中创建该登录名对应的用户test1,若需要将表Person.Address的SELECT权限授予该用户,则对应的SQL脚本如代码5.20所示。
代码5.20使用GRANT授予表的SELECT权限 USEAdventureWorks2012;GRANTSELECTONPerson.Address--授予SELECT权限TOtest1 这里需要注意的是,GRANT授予权限给了用户test1而不是给登录名testuser1。
运行代码5.20后,使用testuser1登录将可以看到AdventureWorks2012数据库中有一个表Person.Address,如图5.17所示。
·176· 图5.17使用testuser1登录后看到的内容 第5章SQLServer2012安全 同样地,如果要将存储过程GetDeparment的执行权限授予test1用户,则对应的SQL授权脚本如代码5.21所示。
代码5.21使用GRANT授予存储过程的执行权限USEAdventureWorks2012;GRANTEXECUTEONdbo.GetDeparment--授予执行权限TOtest1 注意:若只是授予了EXECUTE权限给存储过程,那么该用户只有执行权限,而无法查 看该存储过程的定义,在该用户看来存储过程相当于是被加密了的。
5.6.3使用DENY显式拒绝访问对象 DENY命令用于显式的拒绝用户访问指定的目标对象。
SQLServer中采用“拒绝大于一切”的权限管理机制,如果一个用户属于某个角色或拥有某个架构,而这些角色和架构中定义了对某数据库对象的访问权限,若该用户也被定义了拒绝访问该对象,则最终该用户将无法访问该对象,这就是“拒绝大于一切”的权限管理机制。
DENY命令的语法格式与GRANT的语法格式相似,其语法如代码5.22所示。
代码5.22DENY的语法DENY{ALL[PRIVILEGES]} |permission[(column[,...n])][,...n][ON[class::]securable]TOprincipal[,...n][CASCADE][ASprincipal] 其中:ALL关键字用于表示拒绝该对象上可以应用的所有权限,如果不是ALL关键字, 那么就要在被拒绝的对象上提供一个或多个特定许可权。
PRIVILEGES同样是为了提供兼容性而使用的。
ON关键字后跟要拒绝的对象。
以上关键字与GRANT命令中的意义相同,CASCADE关键字与GRANT语句中的WITHGRANTOPTION对应,CASCADE表示拒绝该用户已经在WITHGRANTOPTION规则下授予访问权的任何人。
同样以前面提到的testuser1为例,前面已经将Person.Address的SELECT权限授予了该登录名对应的用户test1,现在要将整个HumanResources架构的SELECT权限授予该用户,但是不希望该用户查看HumanResources.Employee表,这里需要显式拒绝访问该表。
具体执行脚本如代码5.23所示。
代码5.23使用DENY显式拒绝访问表 use[AdventureWorks2012]GOGRANTSELECTONSCHEMA::HumanResourcesTOtest1--查看该架构下的所有表GO ·177· 第2篇数据库安全 --拒绝查看HumanResources.Employee表DENYSELECTONHumanResources.EmployeeTOtest1 5.6.4使用REVOKE撤销权限 REVOKE语句消除了以前执行GRANT或DENY语句的影响,把这条语句当做“撤销”语句。
REVOKE语句的语法与GRANT和DENY类似,如代码5.24所示。
代码5.24REVOKE语句的语法格式 REVOKE[GRANTOPTIONFOR]{[ALL[PRIVILEGES]]|permission[(column[,...n])][,...n]}[ON[class::]securable]{TO|FROM}principal[,...n][CASCADE][ASprincipal] 同样地,ALL关键字表示要撤销对象类型的所有权限,如果不使用ALL,则必须指定 要撤销该对象的一个或多个特定许可权。
PRIVILEGES仍然是维持兼容性的一个关键字。
ON关键字后显示了要撤销权限的对象。
CASCADE关键字与GRANT语句中的WITHGRANTOPTION对应,CASCADE 表示要撤销在WITHGRANTOPTION规则下授予用户的权限。
AS关键字说明了希望基于哪个角色执行该命令。
仍然以前面使用到的testuser1为例,前面已经对该登录名对应的用户test1授予了 HumanResources架构和Person.Address表的SELECT权限,另外还拒绝了对 HumanResources.Employee表的SELECT权限。
这里若不希望再对HumanResources架构具 有SELECT权限,则撤销该权限的脚本如代码5.25所示。
代码5.25使用REVOKE撤销权限 USEAdventureWorks2012GO REVOKESELECTONSCHEMA::HumanResourcesTOtest1 --撤销对架构的SELECT权限 注意:撤销了对HumanResources架构的SELECT权限,并不会同时撤销对 HumanResources.Employee表的拒绝访问权限。
虽然HumanResources.Employee表属于HumanResources架构,但是在SQLServer中将分别作为单独的数据库对象来对待。
5.6.5语句执行权限 前面介绍的都是针对数据库对象的权限操作,但是数据库权限并不仅仅局限于数据库 ·178· 第5章SQLServer2012安全 对象,另外也包括不能立即连接到特定对象的某种SQL语句。
SQLServer提供了控制权限的许多语句,包括CREATEDATABSE、CREATEDEFAULT、CREATEPROCEDURE、CREATERULE、CREATETABLE、CREATEVIEW、BACKUPDATABASE和BACKUPLOG。
这些语句已经在前面的章节中已经做了介绍,这里就不再详述。
对于这些语句,它们的权限控制其实和其他数据库对象的权限控制是类似的。
这里以创建数据库为例,要为testuser1登录名创建数据库的权限,那么首先该登录名必须要有对master数据库的访问权限。
所以需要先在master中创建该登录名对应的用户,然后再为该用户授予CREATEDATABASE权限。
具体SQL脚本如代码5.26所示。
代码5.26授予用户创建数据库权限 USEmaster;GOCREATEUSERmaster1FORLOGINtestuser1GOGRANTCREATEDATABASETOmaster1 --授予创建数据库权限 运行代码5.26后便可以使用testuser1登录然后创建数据库。
默认情况下,该登录名将在创建的数据库中创建对应的用户dbo,该用户对数据库内的对象具有完全的访问权限。
注意:只为用户授予了CREATEDATABASE权限后,该用户可以创建数据库也可以删 除其创建的数据库,但是该用户不能修改其创建的数据库。
用户必须要对数据库拥有ALTER权限才能使用ALTERDATABASE命令删除数据库。
同样,如果要拒绝用户的语句执行权限则使用DENY命令,如拒绝用户master1的创建数据库的权限,则对应的SQL脚本如代码5.27所示。
代码5.27拒绝创建数据库 USEmasterGODENYCREATEDATABASE--拒绝创建数据库权限TOmaster1 如果需要撤销对用户的语句执行权限的限制,则使用REVOKE命令。
具体SQL脚本如代码5.28所示。
代码5.28撤销创建数据库权限 USEmasterGOREVOKECREATEDATABASE--撤销创建数据库权限TOmaster1 最后,若不再使用testuser1的创建数据库权限,也不再使用master数据库,那么可以执行: DROPUSERmaster1 ·179· 第2篇数据库安全 删除该登录名在master数据库中的用户,从而禁止对master数据库的访问。
5.6.6使用SSMS管理用户权限 SSMS同样提供了大部分用户权限的管理界面,用户可以通过SSMS简单、快捷方便地设置用户的权限。
假设新建一个登录名testuser2,密码为123,该登录名对AdventureWorks2012数据库下的Person架构下的表有查询权限,对Person.AddressType表有更改权限,那么要实现这样的配置需要以下几步操作。

(1)使用sa或者Windows账户登录SSMS,在对象资源管理器中展开“安全性”节点下的“登录名”节点。

(2)右击“登录名”节点,在弹出的快捷菜单中选择“新建登录名”选项,系统弹出“登录名-新建”对话框。

(3)在“常规”选项的右边窗口中输入新建的登录名和密码等信息,如图5.18所示。
图5.18新建登录名
(4)在“用户映射”选项中选中AdventureWorks2012数据库左边的映射复选框,然后将“用户”列的值testuser2修改为user2,这就是要创建的对应的用户,默认架构为dbo,如图5.19所示。

(5)单击“确定”按钮,系统将创建登录名testuser2和在AdventureWorks数据库中对应的用户user2,在对象资源管理器中将看到创建的用户,如图5.20所示。

(6)在其中右击user2,在弹出的快捷菜单中选择“属性”选项,系统将弹出“数据库用户-user2”对话框。
·180· 第5章SQLServer2012安全 图5.19用户映射 图5.20创建好的user2用户
(7)选择“安全对象”选项,切换到用户权限配置对话框,该对话框中显示了当前用户拥有的权限,如图5.21所示。
其中并没有显示任何内容,是因为刚创建的用户并没有授予任何权限。
·181· 第2篇数据库安全 图5.21用户权限配置
(8)单击“搜索”按钮,系统将弹出“添加对象”对话框,如图5.22所示。
该对话框中的“特定对象”单选按钮主要用于查找选择一个架构、一个表和一个存储过程等;“特定类型的所有对象”单选按钮就是按照类型分类,将一种类型的所有对象列出,主要用于多个同类型对象的权限操作。
而“属于该架构的所有对象”单选按钮用于更快速地选出架构对象,这里选中“特定对象”单选按钮。
图5.22“添加对象”对话框
(9)单击“确定”按钮,系统弹出“选择对象”对话框,如图5.23所示。
(10)单击“对象类型”按钮,系统弹出“选择对象类型”对话框,该窗口列出了所有的对象类型,如图5.24所示。
(11)选中“架构”复选框,单击“确定”按钮,系统回到图5.23所示的对话框。
在 ·182· 第5章SQLServer2012安全 该对话框中单击“浏览”按钮,系统弹出“查找对象”对话框,该对话框列出了当前数据库中的所有架构,如图5.25所示。
图5.23“选择对象”对话框 图5.24“选择对象类型”对话框 图5.25“查找对象”对话框 ·183· 第2篇数据库安全 (12)选中[Person]复选框,然后单击“确定”按钮,系统回到图5.23所示的对话框。
在该对话框单击“确定”按钮,系统回到数据库用户权限设置的对话框,如图5.26所示。
图5.26用户权限设置 (13)这里需要为Person架构设置SELECT权限,所以在“显式”选项卡的权限列表中将Select权限的授予复选框选中。
(14)再次单击“搜索”按钮,用同样的方法找到Person.AddressType表,然后将该表的Update权限的授予复选框选中,如图5.27所示。
·184· 图5.27授予用户Update权限 第5章SQLServer2012安全 (15)单击“确定”按钮,用户user2将具有授予的权限。
通过以上操作,登录名testuser2对应的user2将对Person架构的表具有SELECT权限, 对Person.AddressType具有UPDATE权限。
若现在需要对权限进行修改,使user2用户不再对Person.AddressType具有UPDATE权限,只需要重新打开user2的权限设置窗口,不选中Person.AddressType的Update授予选项即可,这相当于执行REVOKE命令。
要显式拒绝对该表的Update权限,则选中Update拒绝选项即可,这相当于执行DENY命令。
另外,语句执行权限并不在用户的属性中进行设置,而是在登录名的属性中进行设置。
例如要将创建数据库的权限授予testuser2登录名则对应的操作为:
(1)在对象资源管理器中展开“安全性”节点下的“登录名”节点。

(2)右击testuser2节点,在弹出的快捷菜单中选择“属性”选项,系统将弹出该登录名的属性对话框,如图5.28所示。
图5.28登录名的属性对话框
(3)选择“安全对象”选项,系统切换到对登录名的权限配置窗口,如图5.29所示。
图5.29登录名安全对象窗口 ·185· 第2篇数据库安全
(4)用类似与为用户授予权限的方式,找到服务器(这里服务器名为IBM-PC),然后将“创建任意数据库”权限的授予复选框选中,如图5.30所示。
图5.30为登录名授予创建数据库权限
(5)单击“确定”按钮,系统将授予testuser2创建数据库的权限。
5.7角色管理 无论是在操作系统、一般业务软件系统还是在数据库管理中,角色都是一个很重要的概念,角色的出现极大地简化了权限管理。
本节将主要讲解数据库中角色的使用。
5.7.1角色简介 角色是一个访问权限的集合,只要给用户分配一个角色,就可以给这个用户全部分配这个权限集合。
角色类似于Windows操作系统中的工作组的概念。
一个用户可以同时拥有多个角色。
因为可以把用户访问权限分成更小的和更合逻辑的组并混合组成更适合用户的规则,所以角色极大地简化了权限的分配管理操作。
角色分为两类:服务器角色和数据库角色。
除了这两种角色类型外,SQLServer2012中还有一种角色被称为应用程序角色。
应用程序角色是一个数据库主体,它使应用程序能够用其自身的、类似用户的权限来运行。
·186· 第5章SQLServer2012安全 这其中服务器级角色也称为“固定服务器角色”,因为用户不能创建新的服务器级角色。
服务器级角色的权限作用域为服务器范围。
SQLServer2012中有两种类型的数据库级角色:数据库中预定义的“固定数据库角色”和可以创建的“用户定义数据库角色”。
固定数据库角色是在数据库级别定义的,并且存在于每个数据库中。
下面分别介绍这几种角色。
5.7.2服务器角色 笔者在前面已经提到,服务器角色是固定的不可被用户创建的,用户在安装完成SQLServer2008时所有的服务器角色就已经存在。
用户可以向服务器级角色中添加SQLServer登录名、Windows账户和Windows组。
固定服务器角色的每个成员都可以向其所属角色添加其他登录名。
SQLServer2012中常用的服务器角色和说明如表5.2所示。
表5.2服务器角色 固定服务器角色 服务器级权限 说明 bulkadmin 已授予:ADMINISTERBULKOPERATIONS 可以运行BULKINSERT批量插入语句 dbcreator 已授予:CREATEDATABASE 可以创建、更改、删除和还原任何数据库 Diskadmin 已授予:ALTERRESOURCES 用于管理服务器的磁盘文件 Processadminsecurityadmin 已授予:ALTERANYCONNECTION、ALTERSERVERSTATE 已授予:ALTERANYLOGIN 可以终止在SQLServer实例中运行的进程 可以管理实例中的登录名及其属性 serveradminsetupadmin 已授予:ALTERANYENDPOINT、ALTERRESOURCES、ALTERSERVERSTATE、ALTERSETTINGS、SHUTDOWN、VIEWSERVERSTATE 已授予:ALTERANYLINKEDSERVER 可以更改服务器范围的配置选项和关闭服务器 可以在实例中添加和删除链接服务器 sysadmin 已使用GRANT选项授予:CONTROLSERVER 超级权限,可以在服务器上执行任何活动 如果将服务器角色赋予登录名,则需要使用系统存储过程sp_addsrvrolemember。
该存储过程的语法为: sp_addsrvrolemember[@loginame=]'login',[@rolename=]'role' 其中[@loginame=]'login'是添加到固定服务器角色中的登录名。
login的数据类型为sysname,无默认值。
login可以是SQLServer登录或Windows登录。
如果未向Windows登录授予对SQLServer的访问权限,则将自动授予该访问权限。
[@rolename=]'role'是要添加登录的固定服务器角色的名称。
role的数据类型为sysname,默认值为NULL,且必须为固定服务器角色中的一个。
例如现在有登录名testuser1,要赋予该登录名dbcreator的服务器角色,那么对应的SQL脚本为: EXECsp_addsrvrolemember'testuser1','dbcreator' ·187· 第2篇数据库安全 对应于赋予用户角色的sp_addsrvrolemember命令,SQLServer2012同样提供了sp_dropsrvrolemember命令,用于从服务器角色中删除SQL登录名或Windows用户或组。
sp_dropsrvrolemember的语法为: sp_dropsrvrolemember[@loginame=]'login',[@rolename=]'role' 各参数的含义与sp_addsrvrolemember的参数含义相同,这里就不再重复介绍。
例如,要将刚为testuser1添加的dbcreator角色去掉,那么对应的SQL脚本为: EXECsp_dropsrvrolemember'testuser1','dbcreator' 在SSMS中,对登录名或Windows用户或组的服务器角色操作也十分方便,主要操作步骤如下所述。

(1)在SSMS的对象资源管理器中展开“安全性”节点下的“登录名”节点。

(2)双击需要配置服务器角色的登录名或者右击该登录名,在弹出的快捷菜单中选择“属性”选项,系统将弹出“登录属性”对话框。

(3)单击“服务器角色”选项,系统将切换到服务器角色配置的窗口,如图5.31所示。
图5.31服务器角色配置
(4)选择需要赋予的角色,然后单击“确定”按钮即可完成服务器角色的配置。
注意:在SSMS中看到服务器角色中有public这样一个角色,但是该角色其实并不是服 务器角色,而是公共角色,不能通过sp_dropsrvrolemember命令取消登录名的public角色。
public角色拥有VIEWANYDATABASE权限。
·188· 第5章SQLServer2012安全 5.7.3固定数据库角色 与固定服务器角色类似,SQLServer2012中也提供了固定的数据库角色。
固定数据库角色主要是为了简化权限配置过程,所以大部分固定的数据库角色其实可以通过用户定义的数据库角色来实现,但是仍有部分固定数据库角色是不可替代的。
如表5.3列出了固定数据库角色对应的权限。
固定数据库角色db_essadmindb_essadmindb_backupoperatordb_datareaderdb_datawriter db_ddladmin db_denydatareaderdb_denydatawriterdb_ownerdb_securityadmin 表5.3固定数据库角色的权限 数据库级权限 已授予:ALTERANYUSER、CREATESCHEMA 已使用GRANT选项授予:CONNECT已授予:BACKUPDATABASE、BACKUPLOG、CHECKPOINT 已授予:SELECT 已授予:DELETE、INSERT、UPDATE 已授予:ALTERANYASSEMBLY、ALTERANYASYMMETRICKEY、ALTERANYCERTIFICATE、ALTERANYCONTRACT、ALTERANYDATABASEDDLTRIGGER、ALTERANYDATABASEEVENT、NOTIFICATION、ALTERANYDATASPACE、ALTERANYFULLTEXTCATALOG、ALTERANYMESSAGETYPE、ALTERANYREMOTESERVICEBINDING、ALTERANYROUTE、ALTERANYSCHEMA、ALTERANYSERVICE、ALTERANYSYMMETRICKEY、CHECKPOINT、CREATEAGGREGATE、CREATEDEFAULT、CREATEFUNCTION、CREATEPROCEDURE、CREATEQUEUE、CREATERULE、CREATESYNONYM、CREATETABLE、CREATETYPE、CREATEVIEW、CREATEXMLSCHEMACOLLECTION、REFERENCES 已拒绝:SELECT 已拒绝:DELETE、INSERT、UPDATE 已使用GRANT选项授予:CONTROL 已授予:ALTERANYAPPLICATIONROLE、ALTERANYROLE、CREATESCHEMA、VIEWDEFINITION 服务器级权限已授予:VIEWANYDATABASE无已授予:VIEWANYDATABASE已授予:VIEWANYDATABASE已授予:VIEWANYDATABASE 已授予:VIEWANYDATABASE 已授予:VIEWANYDATABASE无已授予:VIEWANYDATABASE已授予:VIEWANYDATABASE 如表5.4给出了每个数据库角色的说明。
·189· 第2篇数据库安全 服务器级角色名称db_owner db_securityadmin db_essadmin db_backupoperatordb_ddladmindb_datawriterdb_datareaderdb_denydatawriterdb_denydatareader 表5.4固定数据库角色说明说明 数据库所有者,可以执行数据库的所有配置和维护活动,还可以删除数据库安全相关管理,可以修改角色成员身份和管理权限。
向此角色中添加主体可能会导致意外的权限升级访问管理,可以为Windows登录名、Windows组和SQLServer登录名添加或删除数据库访问权限备份管理角色,可以备份数据库数据定义管理,可以在数据库中运行任何数据定义语言DDL命令可修改数据,可以在所有用户表中添加、删除或更改数据只读角色,可以从所有用户表中读取所有数据不能添加、修改或删除数据库内用户表中的任何数据不能读取数据库内用户表中的任何数据 要将数据库角色赋予数据库用户或者Windows用户或组,SQLServer2012提供了系统存储过程sp_addrolemember。
该存储过程的语法为: sp_addrolemember[@rolename=]'role',[@membername=]'security_ount' 其中,[@rolename=]'role'为当前数据库中的数据库角色名称。
role数据类型为sysname,无默认值。
[@membername=]'security_ount'是添加到该角色的安全账户。
security_ount数据类型为sysname,无默认值。
security_ount可以是数据库用户、数据库角色、Windows登录或Windows组。
例如在AdventureWorks2012数据库中有数据库用户test1,现在希望该用户能够以只读的方式访问该数据库,那么可以为该用户赋予db_datareader角色。
具体SQL脚本如代码5.29所示。
代码5.29赋予test1用户db_datareader角色 USE[AdventureWorks2012]GOEXECsp_addrolemember'db_datareader','test1'--为用户添加角色GO 除了为用户添加角色外,SQLServer2012也提供了系统存储过程sp_droprolemember,用于将用户从角色中删除。
该存储过程的语法为: sp_droprolemember[@rolename=]'role',[@membername=]'security_ount' 各参数含义与sp_addrolemember相同,这里就不再重述。
例如需要将AdventureWorks数据库中的数据库用户test1从db_datareader角色中删除,那么对应的SQL脚本如代码5.30所示。
代码5.30删除test1用户的db_datareader角色 USE[AdventureWorks2012]GOEXECsp_droprolemember'db_datareader','test1'--删除test1用户的db_ ·190· 第5章SQLServer2012安全datareader角色GO 同样以AdventureWorks2012数据库中的test1为例,在SSMS中要向固定数据库角色添加或删除用户的主要操作如下所述。

(1)在SSMS的对象资源管理器中依次展开数据库、AdventureWorks2012、安全、用户等节点。

(2)双击test1用户节点或右击该节点,在弹出的快捷菜单中选择“属性”选项,系统将弹出“数据库用户”对话框,如图5.32所示。
图5.32“数据库用户”对话框
(3)在该对话框单击“成员身份”选项,如图5.33所示。
列出了当前用户所能拥有的数据库角色,选中要赋予的角色,取消选中不需要赋予的角色。

(4)单击“确定”按钮,就完成了对用户数据库角色的配置。
5.7.4用户定义数据库角色 固定的数据库角色有助于帮助用户快速地配置权限,但是安全性中的核心任务是创建和分配用户定义的数据库角色,这些角色可以决定它们包含什么样的许可权。
对于用户定义的数据库角色,可以用处理数据库用户的方法一样授权、拒绝和回收权限。
使用角色进行权限配置,可以通过修改角色这一个地方而把权限修改应用到每一个配置该角色的用户上。
要创建用户第一的数据库角色,SQLServer2012提供了CREATEROLE命令,该命令的语法为: CREATEROLErole_name[AUTHORIZATIONowner_name]·191· 第2篇数据库安全 图5.33“成员身份”选项 其中role_name为待创建角色的名称。
AUTHORIZATIONowner_name将拥有新角色的数据库用户或角色。
如果未指定用户,则执行CREATEROLE的用户将拥有该角色。
例如要在AdventureWorks2012数据库中创建角色HRReader,该角色拥有对HumanResources架构表的SELECT权限,那么对应的SQL语句如代码5.31所示。
代码5.31创建角色 USEAdventureWorks2012GO CREATEroleHRReader--创建角色名GO GRANTSELECTONSCHEMA::HumanResourcesTOHRReader --角色权限 角色创建后就需要将角色分配给具体的用户。
给用户定义角色添加用户的操作与给固定数据库角色用户添加角色的方法是一样的,都是使用系统存储过程sp_addrolemember。
关于sp_addrolemember的语法和参数,在前面固定数据库角色章节已经做了详细介绍,这里就不重复介绍了。
要向刚建立的角色HRReader中添加用户test1的SQL脚本为: EXECsp_addrolemember'HRReader','test1' 同样,若需要将角色中的用户删除时使用系统存储过程sp_droprolemember。
例如要将test1用户从HRReader角色中移除的SQL脚本为: EXECsp_droprolemember'HRReader','test1' 使用SSMS也可以创建用户定义数据库角色。
以在AdventureWorks2012数据库中创建 ·192· 第5章SQLServer2012安全 角色SalesReader为例,在SSMS中创建用户定义数据库角色的主要操作如下所述。

(1)在SSMS的对象资源管理器中依次展开数据库、AdventureWorks2012、安全性、 角色、数据库角色节点。

(2)右击“数据库角色”节点,在弹出的快捷菜单中选择“新建数据库角色”选项, 系统将弹出“数据库角色-新建”对话框,如图5.34所示。
图5.34“数据库角色-新建”对话框
(3)在“角色名称”文本框中输入要新建的角色SalesReader。

(4)单击“添加”按钮,选出要添加到该角色中的用户,例如test1。

(5)选择“安全对象”选项,系统切换到角色的权限配置窗口,如图5.35所示。
图5.35角色的权限配置窗口
(6)单击“搜索”按钮,接下来的操作与用户权限配置的操作相同,读者若不是很清 ·193· 第2篇数据库安全 楚,可以查看5.6.6节中的内容。

(7)为该用户配置对Sales架构的选择权限,配置后如图5.36所示。
图5.36配置权限
(8)配置完成后单击“确定”按钮,系统将在AdventureWorks2012数据库中建立SalesReader角色,并将test2用户添加到该角色中。
添加成功角色后可以通过对象资源管理器看到新建的角色,如图5.37所示。
·194· 图5.37在对象资源管理器中查看角色 第5章SQLServer2012安全 删除角色非常简单,与删除架构删除用户类似,在SQLServer2012中删除角色使用DROPROLE命令。
例如要删除AdventureWorks2012数据库中创建的角色HRReader,则对应的SQL脚本如代码5.32所示。
代码5.32删除角色USEAdventureWorks2012GODROProleHRReader 注意:无法从数据库删除拥有成员的角色,在要删除用户定义的数据库角色之前必须要 清空该角色中的所有用户;否则将会删除角色失败。
使用SSMS删除角色的操作与删除用户、架构等并没有什么不同。
只需要在SSMS的对象资源管理器中选中该角色,然后使用快捷键Delete,系统将弹出删除对象对话框,单击“确定”按钮即可完成角色的删除。
5.7.5应用程序角色 应用程序角色是特殊的数据库角色,用于允许用户通过特定应用程序获取特定数据。
应用程序角色不包含任何成员,而且在使用它们之前要在当前连接中将它们激活。
激活一个应用程序角色后,当前连接将丧失它所具备的特定用户权限,只获得应用程序角色所拥有的权限。
应用程序角色能够在不断开连接的情况下切换用户的角色和对应的权限。
应用程序角色的使用过程如下:
(1)用户通过登录名或Windows认证方式登录到数据库。

(2)登录有效,获得用户在数据库中拥有的权限。

(3)应用程序执行sp_setapprole系统存储过程并提供角色名和口令。

(4)应用程序角色生效,用户原有角色对应的权限消失,用户将获得应用程序角色对应的权限。

(5)用户使用应用程序角色中的权限操作数据库。
要创建应用程序角色,需要使用SQLServer2012中的CREATEAPPLICATIONROLE命令。
该命令的语法如代码5.33所示。
代码5.33创建应用程序角色语法CREATEAPPLICATIONROLEapplication_role_nameWITHPASSWORD='password'[,DEFAULT_SCHEMA=schema_name] 其中,application_role_name为指定应用程序角色的名称。
该名称不能被用于引用数据库中的任何主体。
PASSWORD='password'用于指定数据库用户将用于激活应用程序角色的密码,应始终使用强密码。
DEFAULT_SCHEMA=schema_name用于指定服务器在解析该角色的对象名时将搜索的第一个架构。
如果未定义DEFAULT_SCHEMA,则应用程序角色将使用DBO作为其默认架构。
schema_name可以是数据库中不存在的架构。
例如,要在AdventureWorks2012数据库中创建应用程序角色PersonReader,该角色的 ·195· 第2篇数据库安全 密码为123,那么对应的SQL脚本如代码5.34所示。
代码5.34创建应用程序角色 USEAdventureWorks2012GOCREATEAPPLICATIONROLE[PersonReader]WITHDEFAULT_SCHEMA=[dbo],PASSWORD='123' 在创建好应用程序角色后接下来就是为该角色分配权限,这里仍然使用GRANT等权 限分配命令。
要将Person架构的表的SELECT权限分配给该角色的脚本如代码5.35所示。
代码5.35 USEAdventureWorks2012;GOGRANTSELECTONSCHEMA::PersonTOPersonReader 为应用程序角色分配权限 应用程序角色的配置已经完成,接下来就是使用了。
首先使用testuser1登录,该登录名在AdventureWorks2012数据库中对应用户test1,该用户对Sales架构的表有选择权限,那么运行代码5.36后,系统将会抛出异常,因为没有对Person.AddressType表的访问权限。
代码5.36使用testuser1访问数据库 USEAdventureWorks2012;GOSELECTTOP10*FROMSales.CustomerGOSELECT*--这里将会抛出异常,因为没有权限访问FROMPerson.AddressTypeGO 要使用应用程序角色,需要调用系统存储过程sp_setapprole。
该存储过程的语法如代 码5.37所示。
代码5.37sp_setapprole的语法 sp_setapprole[@rolename=]'role',[@password=]{encryptN'password'}|[,[@encrypt=]{'none'|'odbc'}][,[@fCreateCookie=]true|false][,[@cookie=]@cookieOUTPUT] 'password' 这里需要最主要的参数是role,即要使用的应用程序角色名,password为该应用程序角色对应的密码。
其他参数都是可选参数,读者若需深入学习可以查看帮助文档。
同样使用testuser1登录,执行代码5.38,系统将会抛出异常,因为当前用户的角色已经切换到应用程序角色中,用户不再对Sales.Customer表具有访问权限。
代码5.38USEAdventureWorks2012; 激活应用程序角色 ·196· 第5章SQLServer2012安全 GOEXECsp_setapprolePersonReader,'123'--激活应用程序角色GOSELECTTOP10*--这里抛出异常,因为应用程序角色PersonReader并没有对该表的访问 权限FROMSales.CustomerGOSELECT*--正常访问FROMPerson.AddressType 注意:应用程序角色是单向的,也就是说当前用户一旦切换到应用程序角色将不能再切 换回原来的角色中。
若需要使用原来用户的角色只有终止当前连接并重新登录。
若要删除应用程序角色,需要使用DROPAPPLICATIONROLE命令。
例如要删除前面创建的应用程序角色PersonReader,则对应的SQL脚本如代码5.39所示。
代码5.39删除应用程序角色 USEAdventureWorks2012;GODROPAPPLICATIONROLEPersonReader 在SSMS中以在AdventureWorks2012数据库中创建应用程序角色PersonReader为例,在SSMS中创建该应用程序角色的主要操作步骤如下所述。

(1)在SSMS的对象资源管理器中依次展开数据库、AdventureWorks2012、安全性、角色、应用程序角色节点。

(2)右击“应用程序角色”节点,在弹出的快捷菜单中选择“新建应用程序角色”选项,系统将弹出“应用程序角色-新建”对话框,如图5.38所示。
图5.38“应用程序角色-新建”对话框 ·197· 第2篇数据库安全
(3)在“角色名称”文本框中输入要新建的角色名PersonReader,在“默认架构”文本框中输入dbo,在“密码”和“确认密码”文本框中输入角色的密码123。

(4)选择“安全对象”选项,系统切换到应用程序角色的权限配置窗口。

(5)应用程序角色的权限配置和数据库角色的权限配置及用户的权限配置对话框相同,用同样的操作为该角色配置对Person架构的SELECT权限(读者若不清楚如何操作,可以参看前面的“使用SSMS管理用户权限”小节)。
配置后如图5.39所示。
图5.39配置应用程序角色权限
(6)单击“确定”按钮即可完成应用程序角色的创建。
若要在SSMS中删除应用程序角色,其操作和删除用户数据库角色相同。
在对象资源 管理器中选中需要删除的应用程序角色,然后使用快捷键Delete,在弹出的删除对象对话框中单击“确定”按钮即可实现删除操作。
5.8数据加密 在评估安全框架的过程中,企业的IT部门可能需要重新评估整个组织的安全性。
这些安全措施可包括前面提到的密码策略、审核策略、数据库服务器隔离,以及应用程序验证和授权控制。
但是,保护敏感数据的最后一个安全屏障通常是数据加密,本节将主要讲解数据加密在SQLServer中的应用。
·198· 第5章SQLServer2012安全 5.8.1数据加密简介 加密是一种帮助保护数据的机制。
加密是通过使用特定的算法将数据打乱,达到只有经过授权的人员才能访问和读取数据的目的,从而帮助提供数据的保密性。
当原始数据(称为明文)与称为密钥的值一起经过一个或多个数学公式处理后,数据就完成了加密。
此过程使原始数据转为不可读形式。
获得的加密数据称为密文。
为使此数据重新可读,数据接收方需要使用相反的数学过程以及正确的密钥将数据解密。
然而,加密时需要执行某种算法,此过程会增加计算机处理器时间,加密后的密文一般会比明文数据大,密文的存储也需求更多的成本。
较长的加密密钥比较短的加密密钥更有助于提高密文的安全性。
不过,较长的加密密钥的加密/解密运算更加复杂,占用的处理器时间也比较短的加密密钥长。
一般有以下两种主要加密类型: 对称加密。
此种加密类型又称为共享密钥加密。
非对称加密。
此种加密类型又称为两部分加密或公共密钥加密。
对称加密使用相同的密钥加密和解密数据,如图5.40所示。
对称加密使用的算法比用于非对称加密的算法简单。
由于这些算法更简单以及数据的加密和解密都使用同一个密钥,所以对称加密比非对称加密的速度要快得多。
因此,对称加密适合大量数据的加密和解密。
常用的对称加密算法有:RC2(128位)、3DES和AES等。
非对称加密使用两个具有数学关系的不同密钥加密和解密数据。
这两个密钥分别称为私钥和公钥。
它们合称为密钥对。
使用密钥对进行加密解密的过程如图5.41所示。
非对称加密被认为比对称加密更安全,因为数据的加密密钥与解密密钥不同。
但是,由于非对称加密使用的算法比对称加密更复杂,并且还使用了密钥对,因此当组织使用非对称加密时,其加密过程比使用对称加密慢很多。
常用的非对称加密算法有:RSA和DSA。
图5.40对称加密 图5.41非对称加密 注意:加密不仅对CPU和内存造成一定的性能影响,加密后的数据占用的存储空间也 会有所改变,加密后数据大小取决于使用的算法、密钥的大小和明文的大小。
SQLServer2012提供了内置的数据加密功能,并支持以下3种加密类型,每种类型使用一种不同的密钥,并且具有多个加密算法和密钥强度。
对称加密:SQLServer2012中支持RC4、RC2、DES和AES系列加密算法。
非对称加密:SQLServer2012支持RSA加密算法,以及512位、1024位和2048 位的密钥强度。
证书:使用证书是非对称加密的另一种形式。
但是,一个组织可以使用证书并通 过数字签名将一组公钥和私钥与其拥有者相关联。
SQLServer2012支持“因特网工程工作组”(IETF)X.509版本3(X.509v3)规范。
一个组织可以对SQLServer ·199· 第2篇数据库安全 2012使用外部生成的证书,或者可以使用SQLServer2012生成证书,证书可以以独立文件的形式备份,然后在SQLServer中进行还原。
SQLServer2012用分层加密和密钥管理基础结构来加密数据。
每一层都使用证书、非对称密钥和对称密钥的组合对它下面的一层进行加密,顶级(服务主密钥)是用WindowsDPAPI加密的。
如图5.42所示的加密层次结构与权限层次结构中介绍的安全对象的层次结构相似。
图5.42加密层次结构 5.8.2数据的加密和解密 在对加密和解密有了一个基本的概念后,本小节将在SQLServer中对数据进行加密和解密。
SQLServer中有些数据列是十分敏感的,例如用户的密码、信用卡号、员工的工资等,这些数据如果未经过加密,一旦数据库内容泄露,将造成不可估量的损失。
所以,在SQLServer中需要将这些数据库进行加密后保存,这样即使数据库文件被盗,别人在没有密钥的情况下是无法查看这些敏感数据的。
以一个测试数据库TestDB1为例,这其中有一个管理员表AdminUser,该表保存了管理员的用户名LoginName和密码Password。
在SQLServer2012中,要使用对称加密算法对Password数据列进行加密主要经过以下几步。

(1)创建数据库主密钥。
数据库主密钥又叫服务主密钥,为SQLServer加密层次结构的根。
服务主密钥是首次需要它来加密其他密钥时自动生成的。
默认情况下,服务主密钥使用Windows数据保护API和本地计算机密钥进行加密。
只有创建服务主密钥的Windows服务账户或有权访问服务账户名称和密码的主体能够打开服务主密钥。
SQLServer中的数据库级别加密功能依赖于数据库主密钥。
创建数据库时不会自动生成该密钥,必须由系统管理员创建,仅需要对每个数据库创建一次主密钥即可。
SQLServer中创建主密钥使用如下命令: CREATEMASTERKEYENCRYPTIONBYPASSWORD='' ·200· 第5章SQLServer2012安全 其中,password为创建主密钥时对主密钥副本进行加密的密码。
这里创建主密钥的脚本如代码5.40所示。
代码5.40创建主密钥 USETestDB1;GOCREATEMASTERKEY--创建主密钥ENCRYPTIONBYPASSWORD='P@ssw0rd'--指定密码
(2)创建一个证书。
SQLServer2012使用证书加密数据或对称密钥。
公钥证书(通常只称为证书)是一个数字签名语句,它将公钥的值绑定到拥有对应私钥的人员、设备或服务的标识上。
证书是由证书颁发机构(CA)颁发和签名的。
从CA处接收证书的实体是该证书的主体。
证书中通常包含下列信息: 主题的公钥。
主题的标识符信息,如姓名和电子邮件地址。
有效期。
这是指证书被认为有效的时间长度。
颁发者标识符信息。
颁发者的数字签名。
说明:证书只有在指定的有效期内有效,每个证书都包含一个“有效期始于”和“有效 期至”日期。
这两个日期设置了有效期的界限。
证书超过有效期后,必须由已过期证书的主题请求一个新证书。
SQLServer提供了CREATECERTIFICATE命令用于创建证书。
这里为加密创建证书的脚本如代码5.41所示。
代码5.41创建证书 USETestDB1;GOCREATECERTIFICATEAdminPwdCert WITHSUBJECT='TOEncryptAdminPassword', EXPIRY_DATE='2013/1/1';--证书的过期日期 --证书的主题
(3)创建一个对称密钥,以加密目标数据。
使用第
(2)步中创建的证书、其他对称密钥或用户提供的密码加密此对称密钥。
SQLServer提供了CREATESYMMETRICKEY命令用于创建对称密钥。
此处使用AES256加密算法用于创建密钥,则对应的脚本如代码5.42所示。
代码5.42创建对称密钥 USETestDB1;GOCREATESYMMETRICKEYPwdKeyWITHALGORITHM=AES_256--使用AES256加密算法ENCRYPTIONBYCERTIFICATEAdminPwdCert;--使用证书加密
(4)打开对称密钥将数据加密或解密。
要打开此密钥,可以使用以下命令: ·201· 第2篇数据库安全 OPENSYMMETRICKEYKey_nameDECRYPTIONBYCERTIFICATEcertificate_name 其中Key_name为要打开的对称密钥的名称。
certificate_name为证书的名称,该证书的私钥将用于解密对称密钥。
这里要打开前面创建密钥PwdKey的脚本如代码5.43所示。
代码5.43打开对称密钥 OPENSYMMETRICKEYPwdKeyDECRYPTIONBYCERTIFICATEAdminPwdCert 注意:打开的对称密钥将绑定到会话而不是安全上下文。
打开的密钥将持续有效,直 到它显式关闭或会话终止。

(5)使用EncryptByKey()函数加密数据,或使用DecryptByKey()函数解密数据。
至此,该数据在数据库中存储为二进制大对象(BLOB)或者被解密,这取决于使用的Transact-SQL语句。
加密函数EncryptByKey()的语法格式为: EncryptByKey(key_GUID,'cleartext') 其中key_GUID为密钥的GUID值,可以通过Key_GUID('key_name')函数获得该值。
第二个参数cleartext就是要加密的明文。
例如要插入加密密码的管理员数据操作如代码5.44所示。
代码5.44插入加密数据 CREATETABLEAdminUser( LoginNamevarchar(50)NOTNULLPRIMARYKEY,Passwordvarbinary(500)NOTNULL)GOINSERTINTOAdminUser VALUES('admin1',EncryptByKey(Key_GUID('PwdKey'), 'p@ssw0rd1')) --加密数据 解密函数DecryptByKey()只需传入密文,该函数将会返回解密出的明文。
注意:DecryptByKey()函数返回的是varbinary数据,需要经过数据类型转换才能阅读。
DecryptByKey()使用对称密钥,该对称密钥必须已经在数据库中打开,可以同时打开多个密钥。
不必只在解密密码之前才打开密钥。
解密并查询数据的脚本如代码5.45所示。
代码5.45解密数据 SELECTLoginName,Password--直接查询的内容将不可读FROMAdminUserSELECTLoginName,CONVERT(varchar(50),DecryptByKey(Password))–解密出明文FROMAdminUser
(6)关闭对称密钥。
关闭对称密钥使用CLOSESYMMETRICKEY命令。
该命令的语法为: ·202· 第5章SQLServer2012安全 CLOSE{SYMMETRICKEYkey_name|ALLSYMMETRICKEYS} 其中CLOSESYMMETRICKEYkey_name为关闭指定的密钥,而CLOSEALLSYMMETRICKEYS为关闭所有打开的密钥。
这里关闭对称密钥的脚本为: CLOSESYMMETRICKEYPwdKey 注意:关闭密钥后加密函数EncryptByKey()和解密函数DecryptByKey()都将无效,必须 重新打开密钥才能使用。
5.8.3使用证书加密和解密 通常情况下,使用对称密钥加密数据,此方法利用了对称加密速度快的优点。
但是也可以使用证书代替对称密钥将数据加密。
由于非对称加密比对称加密更安全,因此,当需要在运行SQLServer2012的多台服务器间传输加密密钥的情况下,使用证书加密数据很有用。
使用证书进行加密和解密主要经过以下几步操作。

(1)创建数据库主密钥。
具体创建操作在5.8.2节已经做了介绍,这里不再重复介绍。
一个数据库中只有一个主密钥,如果已经创建过主密钥就不再重复创建了。

(2)创建一个证书。
具体操作也与5.8.2节介绍的相同。
这里假设需要将员工的工资字段进行加密,创建一个新的证书用于加密,创建脚本如代码5.46所示。
代码5.46创建证书 USETestDB1;GOCREATECERTIFICATEWageCert WITHSUBJECT='TOEncryptWage', EXPIRY_DATE='2013/12/31'; --证书的主题--证书的过期日期
(3)使用证书的公钥加密数据。
使用证书加密数据需要用到EncryptByCert()函数。
该函数返回varbinary类型数据,其语法为: EncryptByCert(certificate_ID,{'ciphertext'|@ciphertext}) 其中,certificate_ID为证书的ID,可以通过Cert_ID('cert_name')函数获得证书ID。
'cleartext'为要进行加密的明文。
使用证书加密工资字段的脚本如代码5.47所示。
代码5.47使用证书加密数据 CREATETABLEEmployee( EmpIDintNOTNULLPRIMARYKEY,Wagevarbinary(500)NOTNULL--工资字段,加密后为二进制数据)GOINSERTINTOEmployeeVALUES(
1,EncryptByCert(Cert_ID('WageCert'),'5000'))--使用证书加密
(4)使用证书的私钥解密数据。
使用证书解密数据需要用到DecryptByCert()函数。
该 函数返回varbinary类型数据,其语法为: DecryptByCert(certificate_ID,{'ciphertext'|@ciphertext}) ·203· 第2篇数据库安全 其中,certificate_ID为证书的ID,'ciphertext'为经过加密后的密文。
使用证书解密工资字段的脚本如代码5.48所示。
代码5.48使用证书解密数据 SELECT*--直接查询数据,Wage字段是加密的FROMEmployeeSELECTEmpID,CONVERT(varchar(50), DECRYPTBYCERT(Cert_ID('WageCert'),Wage))FROMEmployee --使用证书解密Wage字段 注意:使用证书加密是非对称加密操作,将会消耗大量资源,所以不提倡在常用的数据 列上使用。
5.8.4使用透明数据加密 透明数据加密旨在为整个数据库提供静态保护而不影响现有的应用程序。
透明数据加密可对数据和日志文件进行实时的I/O加密和解密。
这种加密使用数据库加密密钥(DEK),该密钥存储在数据库启动记录中以供恢复时使用。
DEK通过存储在服务器的master数据库中的证书来保证安全。
数据库文件的加密在页级执行。
已加密数据库中的页在写入磁盘之前会进行加密,在读入内存时会进行解密。
透明数据加密不会增大已加密数据库的大小。
以对TestDB1数据库使用TDE为例,主要操作步骤如下所述。

(1)创建数据库主密钥。
创建数据库主密钥使用CREATEMASTERKEY命令,前面已经做了介绍,创建脚本如代码5.49所示。
代码5.49创建数据库主密钥USEmaster;GOCREATEMASTERKEY--创建数据库主密钥 ENCRYPTIONBYPASSWORD='password'; 注意:使用TDE时创建的数据库主密钥是在master系统数据库中创建的,而前面提到 的对称加密和证书加密都是在具体的目标数据库中创建的。

(2)创建一个证书。
创建证书使用CREATECERTIFICATE命令,关于证书的创建在前面内容中已经做了介绍。
创建证书的脚本如代码5.50所示。
代码5.50创建证书USEmaster;GOCREATECERTIFICATE--创建证书tdeCertWITHSUBJECT='usetoTDE'; ·204· 第5章SQLServer2012安全 说明:在不指定EXPIRY_DATE参数的情况下,证书默认为从当前时刻生效,1年后 失效。

(3)创建用于以透明方式加密数据库的加密密钥。
在master数据库创建好用于TDE的证书后,接下来就需要使用SQLServer提供的CREATEDATABASEENCRYPTIONKEY命令在需要被加密的数据库中创建加密密钥。
该命令的语法如代码5.51所示。
代码5.51CREATEDATABASEENCRYPTIONKEY命令的语法CREATEDATABASEENCRYPTIONKEY WITHALGORITHM={AES_128|AES_192|AES_256|TRIPLE_DES_3KEY}ENCRYPTIONBYSERVERCERTIFICATEEncryptor_Name 其中,AES_128、AES_192、AES_256、TRIPLE_DES_3KEY都是用于指定加密密钥的加密算法。
Encryptor_Name指定用于加密数据库密钥的加密程序名称,即证书的名称。
假设现在需要对TestDB1数据库使用AES_256加密算法进行透明数据加密,则在该数据库上创建加密密钥的脚本如代码5.52所示。
代码5.52创建加密密钥USETestDB1;GOCREATEDATABASEENCRYPTIONKEYWITHALGORITHM=AES_256--指定加密算法ENCRYPTIONBYSERVERCERTIFICATEtdeCert;
(4)修改数据库,使TDE可用。
创建好加密密钥后数据库并没有进行加密,必须要修改数据库,开启加密选项,使TDE可用。
开启TDE后,系统将在后台开启一个进程进行异步的加密扫描,直到将现有数据库中的所有数据加密完成。
代码5.53用于修改数据库开启TDE加密。
代码5.53修改数据库开启TDEALTERDATABASETestDB1SETENCRYPTIONON--修改数据库,开启透明数据加密 TDE之所以被称为透明数据加密,是因为它只是对数据库的数据文件和日志文件进行加密,对用户和程序而言并不会有任何改变,也就是说,这个加密操作对用户来说是透明的。
用户对数据库的写操作都会由系统将数据加密后再写到数据文件和日志文件上,同样,读操作也是先将加密的数据读取出来由系统解密后再返回给用户。
5.9SQL注入攻击 在数据库应用开发中,有时由于程序员的水平及经验不足,在编写代码时,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。
用户可以提交一段数据库查询代码,根据程序返回的结果获得某些想得知的数据,这就是所谓的SQLInjection,即SQL注入。
·205· 第2篇数据库安全 5.9.1SQL注入攻击原理 SQL注入是由于未对用户输入的数据进行合法性判断造成的。
为了便于读者理解,这里就以一个新闻系统为例,现有一个新闻展示页面News.aspx,该页面根据URL中跟的参数id来决定读取哪一条新闻。
如果为对URL中的参数进行判断,采用拼SQL语法的方式读取新闻数据的程序段如代码5.54所示。
代码5.54读取新闻数据 protectedvoidPage_Load(objectsender,EventArgse){ stringsql="SELECT*FROMNewsWHERENewsID="+Request.QueryString["id"];//这里就是URL中传入的id参数BindNews(sql);//将SQL语句传入,根据SQL语句读取信息} 虽然是使用C#编写,但相信这段代码读者很容易理解。
在正常访问新闻页面时,例如http://xxxxxx/News.aspx?
id=123,那么后台生成的SQL查询语句为: SELECT*FROMNewsWHERENewsID=123 整个语句和逻辑都没有问题,新闻数据被查出并显示在页面上。
那么如果用户在URL后跟了其他信息呢?例如将URL写成http://xxxxxx/News.aspx?
id=123and1=
1,那么后台生成的SQL语句为: SELECT*FROMNewsWHERENewsID=123and1=
1 这个SQL语句也没有问题,数据被正常查出并绑定到页面上。
这时再将参数改为“?
id=123and1=2”,那么生成的SQL语句为: SELECT*FROMNewsWHERENewsID=123and1=
2 显然这样是查不出数据的,页面上显示数据不存在或抛出异常。
通过跟不同的参数,黑客就可以定位这个地方就是SQL注入点了。
既然发现了注入点,那么黑客又能做什么?如果当前读取新闻的用户具有超级管理员权限,那么黑客利用这个注入点,基本上什么都可以做。
这里笔者举一个简单的参数情况,如果参数改为“?
id=123;droptableNews”,那么后台生成的SQL语句就变成了: SELECT*FROMNewsWHERENewsID=123;DROPTABLENews 系统运行该SQL,整个新闻表都被删除了。
另外,利用SQL注入漏洞还可以绕过用户认证,例如用户登录时的后台程序如代码5.55所示。
代码5.55登录验证代码 stringsql="SELECT*FROMAdminUserWHERELoginName=’” +txbloginName.Text //用户输入的用户名 +"’ANDPassword=’"+txbPwd.Text+"’;"//输入的密码 Validate(sql); //根据是否返回数据行来验证用户名密码是否正确 ·206· 第5章SQLServer2012安全 对于正常的用户登录,那么生成的SQL语句为: SELECT*FROMAdminUserWHERELoginName=’admin’ANDPassword=’p@ssw0rd’ 验证用户成功,用户成功登录。
那么如果在用户名中填写为“admin’--”而密码随便填写123,那么后台生成的SQL语句如代码5.56所示。
代码5.56 SELECT*FROMAdminUserWHERELoginName='admin'--'ANDPassword='123' 生成被注入的SQL代码 后面的密码部分AND语句被注释了,只需要通过登录名就可以成功登录。
SQL注入的破坏还不仅于此,利用SQL注入,黑客还可以上传木马、提升权限、获得数据库所有数据,甚至还可以获得登录数据库服务器的管理员权限。
说明:笔者在这里只是简单地讲解一下SQL注入的原理,旨在提高读者的安全意识, 读者若对SQL注入有兴趣可自行研究。
SQL注入攻击是一种黑客行为,读者可以出于学习的目的在自己机器上测试,切不可对互联网上的网站进行攻击破坏。
5.9.2如何防范SQL注入攻击 既然了解了SQL注入的原理,那么就可以使用对应的办法进行防范。
防范SQL注入攻击最推荐的办法就是使用存储过程。
存储过程中将使用参数来传递用户的输入,如对应查询新闻的存储过程如代码5.57所示。
代码5.57 CREATEPROCGetNewsByNewsID@newsIDintASSELECT*FROMNewsWHERENewsID=@newsID 查询新闻的存储过程 由于此处定义了传入的参数必须是整数,所以“123and1=1”等这样的参数是无法传入存储过程的,自然也就无法运行注入的代码。
对于字符串的情况也是一样的,将验证用户的数据库操作写为存储过程,对应脚本如代码5.58所示。
代码5.58验证用户的存储过程 CREATEPROCGetAdminByLoginNameAndPassword@loginNamevarchar(50),@passwordvarchar(50)ASSELECT*FROMAdminUserWHERELoginName=@loginNameANDPassword=@password ·207· 第2篇数据库安全 当用户再在用户名中输入“admin’–”时,整个输入将作为一个字符串参数传入数据库,由于将整个输入作为字符串处理,所以WHERE条件最终变为: WHERELoginName='admin''--'ANDPassword='123' 这样注入对存储过程就无效了。
存储过程能够防止大部分SQL注入的发生,但并不是全部。
如果用户在存储过程中动态拼接SQL语句,然后使用EXEC命令来执行动态SQL语句仍然会造成SQL注入攻击。
防范SQL注入的另外一种办法就是将关键字过滤或替换掉。
例如将“’”符号全部替换为“””符号。
如果用户输入中包含有“--”字符串,由于该字符串在SQL语句中表示注释,可以使用程序将该字符串替换成空字符串。
另外还有些敏感的SQL关键字也可以列入过滤字符串中。
使用字符串过滤后即使在存储过程中动态执行拼写的SQL语句也不会造成注入漏洞。
使用存储过程和字符串过滤的方式就可以防范SQL注入攻击,为了提高用户体验和系统安全性,还可以在客户端做输入合法性检查、限制用户输入长度等。
另外还应该对应用程序使用的账号做严格的权限管理,不要随便将超级管理员账号给应用程序使用。
5.10小结 本章主要讲解了SQLServer2012在数据库安全上的一些特性和相关知识。
主要包括登录名的管理、用户的管理、架构管理、用户权限设置、角色管理、数据加密和SQL注入等。
SQLServer2012通过用户角色权限的方式来实现数据库的权限管理。
用户的权限是指是否允许在数据库特定对象上执行特定行为,由于数据库对象众多,而且执行的行为种类也很多,所以使用角色来管理用户权限。
角色分为服务器角色和数据库角色,服务器角色是固定的不可被用户创建的,数据库角色则可以由用户创建。
在创建角色后可以对角色设置用户权限,然后再对用户设置角色,从而实现了对数据库用户权限的配置。
为了保护敏感数据不被非法获取,SQLServer2012中支持使用密钥和证书对特定字段进行加密和解密。
此外,还可以使用透明数据加密功能,实现对整个数据库的数据文件和日志文件的加密和解密。
·208·

标签: #cpc #creo #马自达 #比例 #cadxy #时间 #图形 #c怎么计算