个性化阅读
专注于IT技术分析

SQL Server 2016始终加密:易于实现,难以破解

本文概述

数据是任何公司的关键资产, 特别是保存商业秘密(例如财务或健康记录)的交易数据。在存储数据的服务器和请求数据的客户端之间的传输过程中, 数据最容易受到攻击。

确保安全的标准方法是加密服务器上的数据, 并使用启用SSL的HTTPS协议来保护传输中的数据。但是, 如果我们可以通过使用HTTPS并通过通信线路以加密格式发送数据, 而仅对具有有效证书的客户端上的数据进行解密, 则可以进一步提高安全级别呢?这种方法会使传统的中间人(MITM)攻击更加困难。

SQL Server加密封面图片

微软针对此问题的解决方案是”始终加密”, 这是一种通过管道发送加密数据并仅由有权访问有效证书的用户解密的方法。因此, 即使攻击者在客户端计算机上没有存储适当的证书的情况下获取数据, 该数据也将毫无用处。

本文介绍了如何设置和使用”始终加密”, 并且建议通过公共通信线路发送重要数据的任何人阅读, 即使这些人受到SSL保护。

始终加密背后的概念

始终加密是Microsoft随SQL Server 2016引入的一种客户端加密技术。始终加密(不仅在写入数据时, 而且在批准的应用程序读取数据时)都对数据进行自动加密。透明数据加密可以实时加密磁盘上的数据和日志文件, 但允许任何查询数据的应用程序读取数据, 而透明数据加密不同于”透明数据加密”, 始终加密要求你的客户端应用程序使用启用了始终加密的驱动程序才能与数据库。通过使用此驱动程序, 该应用程序将加密的数据安全地传输到数据库, 然后该数据库随后只能由有权访问加密密钥的应用程序解密。查询数据的任何其他应用程序也可以检索加密的值, 但是该应用程序在没有加密密钥的情况下无法使用数据, 从而使数据无用。由于采用了这种加密体系结构, 因此SQL Server实例将永远不会看到数据的未加密版本。

目前, 唯一启用了始终加密的驱动程序是用于SQL Server的.NET Framework数据提供程序(需要在客户端计算机上安装.NET Framework 4.6版)和JDBC 6.0驱动程序。时间可能会发生变化, 但这些是2017年4月的官方Always Encrypted要求。

但是为什么我们需要这项技术?使用”始终加密”的原因有两个:

  • 安全性—始终需要确保数据安全。现在, SSL受到威胁, “始终加密”填补了另一层传输管道保护的空白。
  • 法规支持-越来越多的行业法规(主要是在金融和电信行业中), 需要对数据进行加密并防止DBA窥视数据。 PII标准(“个人身份信息”)对此进行了描述, 该标准指出, 必须保护信用卡号, 社会保险号, 姓名和地址之类的东西, 否则数据所有者可能会受到严厉处罚。

如何使用始终加密

使用”始终加密”需要在存储加密表的数据库服务器中进行少量准备。准备过程分为两个步骤:

  • 创建列主键定义
  • 创建列加密密钥

列主密钥

那么什么是列主键?

SQL Server 2016中的列主键

列主密钥是存储在Windows证书存储区(用作演示存储的证书存储选项)中的证书, 第三方硬件安全模块(用于安装, 管理和使用的第三方解决方案的通用名称)证书)或Azure Key Vault(Microsoft用于证书管理的基于云的解决方案)。

正在对数据进行加密的应用程序使用列主密钥来保护用于处理数据库表的列中的数据加密的各种列加密密钥。使用SQL Server的证书存储(有时称为企业密钥管理器)需要使用SQL Server Enterprise Edition。

在本文中, 我们描述了存储在Windows操作系统的Microsoft证书存储中的自签名证书的使用。尽管此方法不是最佳配置, 但它演示了”始终加密”的概念-但还必须指出, 该方法对于生产环境不可接受, 在生产环境中, 证书管理必须使用单独的安全用户帐户进行, 并且最好是, 在单独的服务器上。

你可以使用SQL Server Management Studio(SSMS)中的图形界面或使用T-SQL创建列主键定义。在SSMS中, 连接到你要在其中使用”始终加密”来保护数据库表的SQL Server 2016数据库实例。

创建和使用列主键

在对象资源管理器中, 首先导航到数据库, 然后导航到”安全性”, 然后展开”始终加密的密钥”文件夹以显示其两个子文件夹, 如下图所示:

在SSMS中创建一个密钥。

在SSMS中创建一个密钥。

打开一个新的列主键对话框。

打开一个新的列主键对话框

检查Windows证书存储中密钥的存在。

检查Windows证书存储中密钥的存在

要创建列主键, 请右键单击Column Master Keys文件夹, 然后选择New Column Master Key。在”新建列主密钥”对话框中, 键入列主密钥的名称, 指定是否将密钥存储在当前用户或本地计算机的证书存储区或Azure Key Vault中, 然后在列表中选择一个证书。如果没有证书, 或者要使用新的自签名证书, 请单击”生成证书”按钮, 然后单击”确定”。此步骤将创建一个自签名证书, 并将其加载到运行SSMS的当前用户帐户的证书存储中。

注意:你应该在受信任的计算机上执行这些步骤, 而不要在托管SQL Server实例的计算机上执行这些步骤。这样, 即使主机受到威胁, 数据仍在SQL Server中受到保护。

因此, 在创建证书并将其配置为列主密钥之后, 必须将其导出并将其分发给托管需要访问数据的客户端的所有计算机。如果客户端应用程序是基于Web的, 则必须将证书加载到Web服务器上。如果它是用户计算机上安装的应用程序, 则必须将证书分别部署到每个用户的计算机上。

你可以在以下URL中找到适用于导出和导入操作系统证书的说明:

  • 汇出证明书
    • Windows 7和Windows Server 2008 R2
    • Windows 8和Windows Server 2012
    • Windows 8.1和Windows Server 2012 R2
    • Windows 10和Windows Server 2016
  • 导入证书
    • Windows 7和Windows Server 2008 R2
    • Windows 8和Windows Server 2012
    • Windows 8.1和Windows Server 2012 R2
    • Windows 10和Windows Server 2016

当使用带有加密和解密数据的应用程序将证书导入计算机上的证书存储中时, 必须将证书导入计算机证书存储或运行该应用程序的域帐户的证书存储中。

列加密密钥

创建列主密钥后, 即可准备为特定列创建加密密钥。 SQL Server 2016 ADO.NET驱动程序使用列加密密钥在将数据发送到SQL Server之前对其进行加密, 并在从SQL Server 2016实例检索到数据之后对数据进行解密。与列主密钥一样, 你可以使用T-SQL或SSMS创建列加密密钥。尽管使用T-SQL可以更轻松地创建列主密钥, 但是使用SSMS可以更轻松地创建列加密密钥。

若要创建列加密密钥, 请使用对象资源管理器连接到数据库实例, 导航到数据库, 然后导航到”安全性”, 并展开”始终加密的密钥”文件夹。用鼠标右键单击列加密密钥, 然后选择新建列加密密钥。在”新建列加密密钥”对话框中, 键入新加密密钥的名称, 在下拉列表中选择”列主密钥定义”, 然后单击”确定”。现在, 你可以在新表的定义中使用列加密密钥。

列加密密钥创建

SQL加密:创建列加密密钥,图像1
SQL加密:创建列加密密钥,图像2

创建具有加密值的表

创建列主密钥定义和列加密密钥后, 可以创建一个表来保存加密值。

在执行此操作之前, 必须确定要使用的加密类型, 要加密的列以及是否可以对这些列建立索引。使用”始终加密”功能, 可以正常定义列大小, 然后SQL Server会根据加密设置来调整列的存储大小。创建表之后, 你可能需要更改应用程序以使用”始终加密”在此表上执行命令。

SQL Server 2016加密类型

在创建包含加密值的表之前, 必须确定是否应加密每一列。

首先, 此列将用于查找值还是仅返回这些值?

如果该列将用于查找, 则该列必须使用确定性加密类型, 该类型允许进行相等操作。但是, 使用始终加密功能搜索已加密的数据存在局限性。 SQL Server 2016仅支持相等操作, 包括等于或不等于联接(使用相等)以及使用GROUP BY子句中的值。不支持使用LIKE进行的任何搜索。此外, 必须使用应用程序级别对使用Always Encrypted加密的数据进行排序, 因为SQL Server将基于加密的值而不是解密的值进行排序。

如果该列将不用于查找记录, 则该列应使用随机加密类型。这种加密类型更安全, 但是不支持搜索, 联接或分组操作。

创建带有加密列的表

创建表时, 可以在列定义中使用普通的CREATE TABLE语法和一些其他参数。在CREATE TABLE语句的ENCRYPTED WITH语法内使用了三个参数。

其中第一个是ENCRYPTION_TYPE参数, 该参数接受RANDOMIZED或DETERMINISTIC的值。第二个参数是ALGORITHM参数, 该参数仅接受RAEAD_AES_256_CBC_HMAC_SHA_256的值。第三个参数是COLUMN_ENCRYPTION_KEY, 这是用于加密值的加密密钥。

CREATE TABLE [dbo].[Customers]
(
 [CustomerId] [int] IDENTITY(1, 1), [TaxId] [varchar](11) COLLATE Latin1_General_BIN2 
 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = YOUR_COLUMN_ENCRYPTION_KEY) NOT NULL, [FirstName] [nvarchar](50) NULL, [LastName] [nvarchar](50) NULL, [MiddleName] [nvarchar](50) NULL, [Address1] [nvarchar](50) NULL, [Address2] [nvarchar](50) NULL, [Address3] [nvarchar](50) NULL, [City] [nvarchar](50) NULL, [PostalCode] [nvarchar](10) NULL, [State] [char](2) NULL, [BirthDate] [date] 
 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = YOUR_COLUMN_ENCRYPTION_KEY) NOT NULL
 PRIMARY KEY CLUSTERED ([CustomerId] ASC) ON [PRIMARY] );
 GO

始终加密的索引

包含加密数据的列可用作索引内的关键列, 前提是这些列是使用DETERMINISTIC加密类型进行加密的。当你尝试在这些列上创建索引时, 使用RANDOMIZED加密类型加密的列将返回错误消息。使用任何一种加密类型加密的列都可以用作非聚集索引中的INCLUDE列。

因为加密的值可以作为索引, 所以对于”始终加密”加密的值, 除了通常执行的索引和调整之外, 不需要其他性能调整措施。额外的网络带宽和更大的I / O是返回值的增大导致的唯一副作用。

始终加密的性能

性能始终是关键因素, 尤其是在这种情况下, 当我们将加密开销添加到常规数据库流量中时。测试性能的最佳站点是SQL Performance, 它在各种情况下测试了查询执行和磁盘使用情况:

SQL Server始终加密性能结果测试。

SQL Server Always Encrypted性能结果测试,图像1
SQL Server Always Encrypted性能结果测试,图像2

由于需要通过加密和解密过程来执行CPU和硬盘驱动器工作, 因此对使用的存储空间量和查询持续时间有明显的影响。由于这会影响你的环境(CPU, RAM和磁盘功能), 因此应测试这是否会在生产中出现问题。

注意:如果你想了解有关Microsoft SQL Sever性能优化的更多信息, 请查阅我们以前的文章之一, 如何调整Microsoft SQL Server的性能。

应用变更

你必须采取什么措施才能在旧版代码中正确实施始终加密?

关于SQL Server 2016的始终加密功能的一件好事是, 已经使用存储过程, ORM或参数化T-SQL命令的应用程序应不需要更改应用程序即可使用始终加密, 除非已经使用了非相等操作。直接修改SQL语句作为应用程序内的动态SQL并针对数据库执行这些命令的应用程序, 以使用其查询的参数化(对所有应用程序建议的最佳安全性最佳做法), 然后才能利用始终加密功能。

使始终加密工作所需的另一项更改是在连接到数据库的应用程序的连接字符串中添加了连接字符串属性:列加密设置=启用。

将此设置添加到连接字符串后, ADO.NET驱动程序将询问SQL Server执行命令是否包含任何加密列, 如果包含, 则对哪些列进行加密。对于高负载应用程序, 使用此设置可能不是最佳实践, 尤其是在大部分执行命令不包含加密值的情况下。

因此, .NET Framework在SqlConnection对象上提供了一个名为SqlCommandColumnEncryptionSetting的新方法, 该方法具有三个可能的值:

  • 禁用-没有使用此连接对象执行的查询的”始终加密”列或参数。
  • 已启用-使用此连接对象执行的查询中使用了始终加密列和/或参数。
  • ResultSet —没有始终加密的参数。但是, 使用此连接对象执行查询将返回使用Always Encrypted加密的列。

注意:请注意, 使用此方法可能需要对应用程序代码进行大量更改。另一种方法是重构应用程序以使用不同的连接。

为了获得最佳的SQL Server性能, 明智的做法是, 对于使用”始终加密”的查询, 仅请求”始终加密”的元数据。这意味着在大部分查询使用始终加密的应用程序中, 应启用连接字符串, 并且应用程序中的特定查询应将SqlCommandColumnEncryptionSetting指定为Disabled。对于大多数查询未使用”始终加密”值的应用程序, 不应启用连接字符串, 并且应根据使用”始终加密”列的查询的需要, 为Enabled或ResultSet设置SqlCommandColumnEncryptionSetting。在大多数情况下, 应用程序能够简单地启用连接字符串属性, 并且在使用加密数据时, 应用程序性能将保持不变。

总是值得加密吗?

简短的答案?当然是!

它不仅有助于防止许多潜在的安全隐患, 并为SQL开发人员提供了更多的安全功能, 而且还使你的系统更加合规, 这在从电信到银行业和保险业等多个行业中都至关重要。还需要注意的是, 给定本文中提到的技术先决条件, 可以在对现有系统进行最少应用程序更改的情况下实现始终加密。

尽管你可能会使用自定义解决方案来获得相同的效果, 但是该技术与SQL Server的新版本捆绑在一起, 可以直接使用。同样重要的是, 由于这是一项新技术, 因此在使用上仍然存在一些限制, 并且增加了一些额外的硬件要求。

但是, 除非它们对你的环境不利, 并且你的应用程序分布在公司的Intranet之外, 否则几乎没有理由不使用Always Encrypted。

赞(0)
未经允许不得转载:srcmini » SQL Server 2016始终加密:易于实现,难以破解

评论 抢沙发

评论前必须登录!