本篇文章是SQL Server安全系列的第八篇,详细内容请参考原文。
Relational databases are used in an amazing variety of applications with connections from a dizzying array of clients over widely distributed networks,特别是互联网,使得数据几乎向任何人,任何地方开放。数据库可以包含相当大部分的人类知识,包括高度敏感的个人信息和关键数据。
数据库的这些特性使得有人想要窃取数据或通过篡改以损害它的主人。确保你的数据是安全的是一个关键部分来配置SQL Server和开发应用程序存储数据。这一系列将探索SQL Server 2012安全基础,那样你可以保护你的数据和服务器资源,getting as granular as you need to be to protect against the unique security threats that can affect your data.大部分的功能适用于早期版本的SQL Server,但我也会讨论只适用于SQL Server 2012和以后版本的功能。
一个重要的安全概念是纵深防御,这意味着最好的安全性是分层的,而不是依赖于一个单一的保护层。在你的网络、服务器、SQL Server实例、数据库安全后,可以通过加密敏感数据来添加数据保护的最后一个强大保护层。这一篇将会探索通过加密保护数据,你将了解加密密钥层次结构和各种可用于加密数据的密钥,以及如何管理密钥或让SQL Server为你做这件事。
数据加密
目前为止在这一系列中你已经学习了SQL Server中的很多安全特性来保护你的数据及数据库对象。当你结合网络安全,比如防火墙,用户帐户最小特权,以及其他工具,你的数据就十分安全吗?
不,尽管SQL Server 2012和2014是目前最安全的版本,而且假设你很明智并高效的使用上所有安全特性——被成功攻击还是有可能的。黑客都是极其聪明的人,因此非常有可能某人、某时能攻击到你的数据库服务器并访问你的数据。即使你有百分百的自信认为这样的攻击是不可能的,you might find yourself on the receiving end of an insider attack—a trusted employee gone bad.
一个安全原理是纵深防御——能够帮助你明白如何让你的数据或其他需要保护的资源达到最高级别的安全。纵深防御意味着你不能依赖一个单一的安全措施保护有价值的事物。你应该在不同的安全类型中增加保护层,那样攻击者必须先攻破复杂、困难的障碍才能获取到你的数据。
这也是许多中世纪的城堡有护城河作为第一道防线的原因。下一保护层是一个加强版几米厚的橡木门和石头墙。往往在外墙的里面还会有其他又厚又坚固的墙。就这样一层一层的保护里面人民和宝藏。
类似的方法,SQL Server有许多安全层和工具用于创建维护它们。但是当你的数据极度有价值时,你应该增加最后一道防御:加密。
自从SQL Server2005开始支持数据加密,之后的版本逐一提升功能。你可以使用多种加密类型,同时有多种密钥将数据转换为不可读的(无意义的)数据,除非用户有解密用的密钥。SQL Server支持多种加密算法。而且最棒的是,你可以让SQL Server来管理密钥和保密,这一直是加密中最难的部分。
提示:加密是一个处理器密集型(processor-intensive)操作,因为它需要复杂的计算。一个不合理的查询需要巨大的预读/开销,可能把服务器弄瘫痪。使用加密来保护那些值得加密的数据。
加密密钥
SQL Server可以让你使用任何三种加密密钥。加密密钥是数据的小块,当插入算法,将数据转换成乱码,没有正确的解密密钥几乎是不可能的转换回未加密的值。
->非对称密钥:该类型的加密使用公共/私有密钥对。一个密钥加密数据,另一个密钥进行解密。你可以与任何人分享的公共密钥,以便对任何它们加密数据,只有你可以通过使用私钥解密。SQL Server使用512、1024、2048位的Rivest-Shamir-Adelman(RSA)加密算法。你可以在Wikipedia's RSA page学习更多的RSA算法。
->对称密钥:在这种类型的加密,加密密钥和解密密钥是一样的。有时被称为一个共享的秘密,因为共享数据的双方必须有相同的密钥。在某些情况下,使用对称密钥是很困难的,因为从一方传递秘密到另一方是一个问题。对称密钥是数据库中使用的理想选择,因为它们永远不会离开数据库。SQL Server支持RC4、RC2、DES、AES算法。你可以在Symmetric Encryption查看这些算法。
->证书:证书是非对称密钥加密的一部分,用于公钥加密的数字包装器。SQL Server可以创建供你使用的证书,或者你可以从第三方认证机构获得。SQL Server uses the Internet Engineering Task Force's X.509 specifications.
SQL Server使用加密密钥层次结构,如图8.1所示,加密和保护你在数据库中存储的密钥
图8.1 加密密钥层次结构
在服务器级别,每个数据库实例有一个Service Master Key用于加密低层次的密钥。这个密钥是在SQL Server实例安装时创建。你可以备份和还原它,甚至重新生成,but for the most part you'll leave it alone.SQL Server为你管理,而且你从来不会明确使用它。Service Master Key是存储和保护在Windows,使用Windows Data protection API,or DPAPA.
Service Master Key有一些内部使用,但在这里对于我们而言SQL Server使用它来加密和保护你创建的Database Master Key。在任何你想加密数据的数据库中都需要一个Database Master Key.它是一个对称密钥用于加密和保护任何你创建密钥。你必须显式地在数据库环境中创建它,如代码8.1所示:
-- Set up sample encryption database USE master; GO -- Set up a login IF SUSER_SID('User1') IS NOT NULL DROP LOGIN User1; CREATE LOGIN User1 WITH password = '3f@$fWDY3QvP&K0'; GO IF DB_ID('EncryptionDB') IS NOT NULL DROP DATABASE EncryptionDB; CREATE DATABASE EncryptionDB; GO USE EncryptionDB; GO CREATE USER User1 FOR LOGIN User1; GO USE EncryptionDB; GO -- Databases do not have a master key by default, so you must create it before you can use it: CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'gK#3hbQKDFQY0oF'; GO
代码8.1 在EncryptionDB库中创建Database Master Key
Database Master Key存储两次:它首先被Service Master Key加密存储,然后被你提供的密码再次加密。你可以删除两者中的一个,但不能全删除。通常情况下不会操作它们。
作为对称密钥,Database Master Key在你使用前必须打开它。打开一个密钥加载到内存然后解密,然后就可以使用。因为服务器级的Service Master Key加密了Database Master Key,数据库能自动为你打开密钥,很少需要你显示的去打开。类似Service Master Key,你可以备份、还原、修改Database Master Key.
你将使用图8.1中的其他密钥来加密数据。箭头指示使用哪一个密钥来加密和保护其他的密钥。例如,你可以使用Database Master Key来加密证书或非对称密钥。证书和非对称密钥只能保护对称密钥。对称密钥可以通过证书、非对称密钥或其他对称密钥来保护。
密钥管理
图8.1显示了加密密钥的另一个方面:你可以使用另一个密钥或一个密码来创建密钥。这就是所谓的密钥管理,这是SQL Server能为你管理的一个主要服务。
Key management is the single hardest thing to get right about encryption。历史上充满了各种国家的秘密,当密钥被截取时/泄露。第二次世界大战期间,美国、英国和其他盟国把大量的资源投入到德国和日本使用的加密密钥,以使他们能够拦截和读取高度敏感的信息。在最近的一次,许多高安全的应用程序被攻破,因为攻击者能够找到在应用程序或在计算机上嵌入的密钥。分享秘密是很困难的。
如果选择使用密码你可以自己管理SQL Server加密密钥,然后你肩负着保管密钥的责任。大多数人不想这样做,因为它需要高度专业化的技术技能。但是,如果你想承担这个任务,只要你创建一个密钥时使用密码选项。密码基本上是密钥,你必须确保你可以将密钥保存在安全的位置,并在需要时将其安全传输。
但是你不需要处理这些细节,因为SQL Server将为你照顾密钥管理。它将为你加密新的密钥,使用你所指定的任何方法,并将数据存储为安全地存储任何其他敏感信息。
你有权管理钥匙,但没有一个很好的理由你不应该这样做。
加密数据
现在来看一个SQL Server中加密数据的例子。在这个场景,Customer表通常具有客户的常规信息。客户名称和所在城市,不是敏感数据,不需要加密;但是信用卡类型、帐号可能包含个人敏感信息,应该进行加密。
你将使用一个对称密钥来加密表中的数据,记住一个对称密钥需要一个证书或非对称密钥在数据库中保护。因此,首先使用代码8.2创建一个非对称密钥来保护对称密钥:
-- Create an asymmetric key to protect the new symmetric key CREATE ASYMMETRIC KEY User1AsymmetricKey AUTHORIZATION User1 WITH ALGORITHM = RSA_2048;
代码8.2 创建一个非对称密钥
这个非对称密钥叫做User1AsymmetricKey,被User1用户拥有。这个密钥使用2048位的RSA加密,这是非常强/复杂的加密算法。这类数据肯定是非常非常重要!
接着,使用代码8.3创建一个对称密钥User1SymmetricKey.本例中使用TRIPLE_DES算法,并且被刚才创建的非对称密钥保护:
-- Create a symmetric key, protected by the asymmetric key CREATE SYMMETRIC KEY User1SymmetricKey WITH ALGORITHM = TRIPLE_DES ENCRYPTION BY ASYMMETRIC KEY User1AsymmetricKey;
代码8.3 创建一个对称密钥
如果你想罗列数据库下的对称加密密钥,你可以使用sys.symmetric_keys目录视图来查看。代码8.4执行结果如图8.2所示。注意,因为Database Master Key是一个对称密钥,它也会出现在结果中。
-- List the symmetric keys in the database SELECT * FROM sys.symmetric_keys;
代码8.4 罗列数据库下的对称密钥
图8.2 sys.symmetric_keys目录视图返回结果
代码8.5是EncryptionDB数据库下Customer表的结构:
USE EncryptionDB; GO CREATE TABLE Customer ( CustId int, Name nvarchar(30), City varchar(20), CreditCardType varbinary(1000), CreditCardNumber varbinary(1000), Notes varbinary(4000)); GO -- Grant access on the table to user GRANT SELECT, INSERT ON Customer to User1;
代码8.5 创建Customer表
注意,因为最后三列将会保存加密后的binary类型数据而不是原始的string数据,因此列的类型设置成varbinary。列的长度依赖数据的大小以及算法。数据库有一个User1用户,对Customer表有SELECT和INSERT权限。
是时候加密一些数据并插入到数据库中。第一步使用代码8.6打开对称密钥,这一步引起SQL Server在内部存储查找密钥,确保用户有权限使用密钥,然后解密密钥到内存以准备使用:
OPEN SYMMETRIC KEY User1SymmetricKey DECRYPTION BY ASYMMETRIC KEY User1AsymmetricKey;
代码8.6 打开对称密钥
数据加密使用T-SQL语句EncryptByKey函数,使用唯一的GUID区分密钥。你可以使用Key_GUID函数检索GUID而不是直接传送数值。否则,代码8.7是一个普通的T-SQL插入语句:
INSERT INTO Customer VALUES (1, 'Sally Roe', 'Chatinika', EncryptByKey(Key_GUID('User1SymmetricKey'), 'Visa'), EncryptByKey(Key_GUID('User1SymmetricKey'), '1234-5678-9009-8765'), EncryptByKey(Key_GUID('User1SymmetricKey'), 'One of our best customers. Treat like royalty.'));
代码8.7 插入加密数据
最后一步使用代码8.8关闭对称密钥。它会从内存中移除密钥并释放资源。只要你不需要加密了就应该尽快关闭密钥,因为把它留在内存可能会被攻击者利用。
CLOSE SYMMETRIC KEY User1SymmetricKey;
代码8.8 关闭对称密钥
提示:如果你要使用密钥在一个单独批处理中加密或解密大量的数据,可以它先打开着。打开和关闭密钥需要处理时间的。但是当你完成的时候,别忘了把它关上!
现在运行一个查询语句查看表中的数据,如图8.3所示。你可以看到在CustId、Name、City列数据没有加密,但是在加密列文本是随机binary数据。你的数据是安全的!
图8.3 表中存储的加密数据
表中的数据是没有价值的,除非有一个方法来检索它。本例中你需要使用一个常规查询语句,并且使用DecryptByKey函数来解密数据。这个函数返回varbinary数据,因为加密数据可能是任何数据类型。因此要检索原始文本需要你对DecryptByKey函数结果进行转换。
OPEN SYMMETRIC KEY User1SymmetricKey DECRYPTION BY ASYMMETRIC KEY User1AsymmetricKey; SELECT CustID, Name, City, CONVERT(VARCHAR, DecryptByKey(CreditCardType)) AS CardType, CONVERT(VARCHAR, DecryptByKey(CreditCardNumber)) AS CardNumber, CONVERT(VARCHAR, DecryptByKey(Notes)) AS Notes FROM Customer; CLOSE SYMMETRIC KEY User1SymmetricKey;
代码8.9 打开密钥然后执行查询语句
图8.4 解密数据结果
-- *** Encryption Catalog Views *** -- ******************************** -- Existing keys SELECT * FROM sys.certificates; SELECT * FROM sys.asymmetric_keys; SELECT * FROM sys.symmetric_keys; SELECT * FROM sys.database_principals; SELECT * FROM sys.key_encryptions; SELECT * FROM sys.crypt_properties; -- Information about keys -- Returns a row for each symmetric key encryption specified using the ENCRYPTION BY clause of the CREATE SYMMETRIC KEY statement. SELECT * FROM sys.key_encryptions; -- Returns one row for each cryptographic property associated with a securable SELECT * FROM sys.crypt_properties; -- *** Clean up *** -- **************** USE master; GO IF SUSER_SID('User1') IS NOT NULL DROP LOGIN User1; IF DB_ID('EncryptionDB') IS NOT NULL DROP DATABASE EncryptionDB; GO
总结
SQL Server的数据加密功能为你的数据提供额外的保护层,让你在深度防御。SQL Server攻击者必须攻破网络安全、服务器安全、SQL Server实例的安全性、以及数据库的安全来获得你的数据。然后,与胜利如此接近,他们必须处理强加密的数据才能为其所用。结合强大的数据库安全性,充分利用细粒度的权限以对主体需要访问的数据提供最小特权,你可以为最敏感的数据建立强大的保护。