注意 Microsoft建议不要直接使用证书或非对称密钥来加密数据。非对称密钥加密会将性能降低很多倍,而且你使用这个机制所能保护的数据量是受限的,它取决于密钥模块。你可以使用一个密码而不是数据库主密钥来保护证书和非对称密钥。
服务主密钥是一个管理SQL Server 中所有密钥和证书的密钥。它是SQL Server在安装过程中自动创建的一个同义字密钥。它显然是一个重要的秘密,因为它被知道了的话,那么攻击者就可以解析SQL Server管理的服务器上的每一个密钥。Windows中的数据保护API(Data Protection API ,DPAPI)会保护服务主密钥。
SQL Server为你管理服务主密钥,不过你可以在它上面执行维护任务将它输入到一个文件中,重新生成它,并从一个文件将它恢复回来。然而,大多数情况下你不需要或不想要对密钥做任何修改。对于管理员来说,最好备份他们的服务主密钥,以防密钥崩溃。
在数据库范围内,数据库主密钥是所有密钥、证书和数据库中的数据的根加密对象。每一个数据库可以有一个单独的主密钥;你如果试图创建第二个密钥那你会得到一个错误信息。你必须使用CREATE MASTER KEY Transact-SQL以用户提供的密码来创建一个数据库主密钥:
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'EOhnDGS6!7JKv'
SQL Server 使用从密码和服务主密钥获得的一个三重数据加密标准密钥来加密密钥。第一个拷贝存储在数据库中,第二个拷贝存储在主数据库中。让数据库主密钥由服务主密钥来保护,这使得当需要的时候SQL Server可以自动地解密数据库主密钥。终端应用程序或用户不必使用密码打开主密钥,而且这是将密钥保护于层次之中的一个主要的好处。
分离数据库和一个现有的主密钥,并将它移到另一个服务器上,这是一个棘手的事。问题在于新的服务器的服务主密钥和其它的服务器的服务主密钥是不同的。因此,服务器不能自动地解析数据库主密钥。通过使用加密所采用的密码来打开数据库主密钥并使用ALTER MASTER KEY 语句和新的服务主密钥将它加密,这样可以解决这个问题。否则,你总是需要在使用前打开数据库主密钥。
一旦有了数据库主密钥,开发人员就可以使用它来创建三种密钥类型中的任何一个,这取决于所要求的加密类型:
· 非对称密钥,用于具有一个公共密钥和一个私人密钥对的公共密码匙
· 对称密钥,用于使用相同的密钥进行加密和解密数据的共享秘密的情况下
· 证书,实质上是一个公共密钥的封装
有了这所有的加密选项以及它和服务器以及数据库的深入集成,现在加密已经是一个为你的数据添加最后一道防线的可行方法。但是,要明智地使用这个工具,因为加密会对你的服务器增加许多处理消耗。
透明的数据加密
在SQL Server 2005中,你可以通过编写使用数据库引擎的加密功能的定制Transact-SQL来加密数据库中的数据。SQL Server 2008在这基础上推出了透明数据加密。
透明数据加密执行所有的数据库级别的加密操作,这消除了应用程序开发人员创建定制的代码来加密和解密数据的要求。数据在写到磁盘时进行加密,从磁盘读的时候解密。通过使用SQL Server来透明地管理加密和解密,你可以保护数据库中的业务数据而不必对现有的应用程序做任何修改,如图11所示。

数据库加密密钥(DEK)是用来执行加密和解密的,这个DEK存储在数据库启动记录中,在恢复场景中可用。你可以使用服务主密钥或硬件安全模块(HSM)来保护这个DEK。HSM通常是USB设备或智能卡,因此不容易被偷或丢失。
5.2 可扩展的密钥管理
随着调整遵从性和对数据保密性的整个关注的不断发展,越来越多的公司使用加密作为一种提供深度防范的解决方案。随着公司使用越来越多的加密和密钥来保护他们的数据,密钥管理变得越来越复杂。一些高安全性的数据库使用上千个密钥,而你必须使用一个系统来存储、释放或重建这些密钥。更进一步的,你应该将这些密钥与数据分开存储,以提高安全性。
SQL Server 2008推出了供第三方供应商使用的加密功能。这些解决方案与SQL Server 2005 和SQL Server 2008数据库无缝地合作使用,提供了企业级的专一的密钥管理。这将密钥管理工作从SQL Server移到了专一的密钥管理系统。
SQL Server 2008中的可扩展的密钥管理还支持HSM的使用,从而提供了密钥和数据物理上的分离。
5.3 代码模块签名
在SQL Server 中进行加密的一个好处是它提供了使用证书数字化签名代码模块的功能(存储过程、函数、触发器和事件通知)。这提供了对数据库表和其它对象的访问的更细粒度的控制。像加密数据一样,你使用证书中所包含的私钥来签名代码。结果在签名的代码模块中使用的表只能通过代码来访问,而不允许从代码模块的外部访问到。换句话说,只有使用用来签名这个模块的证书才能访问到这些表。
对于存储过程情况是一样的。例如,如果它有一个没有被破坏的所有权链,你谨慎地控制哪些用户具有对这个存储过程的EXECUTE 权限,而且你直接拒绝对后台的表的访问。但是这在一些情况下不起作用,例如当这个存储过程的所有权链被破坏了或者执行动态的SQL,要求这个用户执行存储过程具有对后台的表的权限。要实现同样目的的另一个方法是使用EXECUTE AS ,但是这会改变存储过程执行环境的安全上下文。这可能是不希望的,例如,如果你需要在表中记录哪个用户使得这个存储过程运行(需要记录作为这个存储过程参数的用户名称)。
签名代码模块还具有保护证书免于对代码模块的未授权的改动的好处。像其它数字签名的文档一样,当代码改变时证书就无效了。代码不在证书的上下文下执行,所以任何具有对该证书的访问权限的对象将不能被访问到。
为了做到这一点,你可以创建一个证书,将它和一个新的用户关联起来,并使用这个证书来签名这个存储过程。为这个用户授权所有执行这个存储过程所必要的权限。实际上,你将这个用户添加到了这个存储过程的安全上下文中作为第二标识。然后将执行权限授予所有需要执行这个存储过程的用户和角色。下面的代码显示了这些步骤。假设你想签名mySchema.GetSecretStuff 存储过程,而所有引用的对象都已经存在于数据库中了:
CREATE CERTIFICATE certCodeSigning
ENCRYPTION BY PASSWORD = 'cJI%V4!axnJXfLC'
WITH SUBJECT = 'Code signing certificate'
GO
-- Sign the stored procedure
ADD SIGNATURE TO mySchema.GetSecretStuff BY CERTIFICATE certCodeSigning
WITH PASSWORD = 'cJI%V4!axnJXfLC'
GO
-- Map a user to the certificate
CREATE USER certUser FOR CERTIFICATE certCodeSigning
GO
--Assign SELECT permissions to new certUser
GRANT SELECT ON SocialSecurity TO certUser
GO
-- Grant execute permission to the user who will run the code
GRANT EXECUTE ON mySchema.GetSecretStuff TO ProcedureUser
GO