65.9K
CodeProject 正在变化。 阅读更多。
Home

SQL Server 2016 中的 Always Encrypted 功能

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (14投票s)

2016年7月6日

CPOL

8分钟阅读

viewsIcon

35383

downloadIcon

1167

该想法旨在实现 Microsoft SQL Server 2016 提供的最新且首创的“Always Encrypted”功能,该功能旨在加密/解密后端数据库引擎中的敏感数据。

想法

该想法旨在实现 Microsoft SQL Server 2016 提供的最新且首创的“Always Encrypted”功能,该功能旨在加密后端数据库引擎中的敏感数据。

摘要

Always Encrypted 允许客户端在客户端应用程序内加密敏感数据,并且永远不会将加密密钥透露给数据库引擎 (SQL Database 或 SQL Server)。因此,“Always Encrypted”在数据所有者(可以查看数据)和数据管理员(无权访问)之间实现了分离。

进程

在本文中,我们将:

  1. 创建一个简单的数据库表,并将其与 ASP.NET MVC 应用程序连接。脚手架控制器和视图来填充数据。如果您熟悉此过程,请直接跳到步骤 2。
  2. 使用 SQL Server 2016 中的 Always Encrypted 功能加密数据库表中的敏感数据列。
  3. 在 ASP.NET MVC 应用程序中进行必要的更改,以自动加密/解密数据。

创建简单的数据库表并将其与 ASP.NET MVC 应用程序连接

第一步是创建一个名为“AlwaysEncryption”的新数据库,表名为“Customer”。假设 Email 和 SSN 列包含敏感信息。

现在数据库已准备就绪,我们将创建一个名为“AlwaysEncryption”的新 ASP.NET Web 应用程序。在此示例中,我将使用 Visual Studio 2015。

从 New ASP.NET Project 模板列表中选择 MVC。由于我们不关注身份验证,请单击“Change Authentication”按钮选择“No Authentication”选项,然后单击OK”。

基本的 Bootstrap MVC 解决方案看起来如下:

现在,在我们的Models文件夹中添加一个新的 Entity Data Model 文件。

在“Entity Data Model”向导中,选择“EF Designer from database”,然后单击“Next”。

在下一个向导屏幕中,选择“Microsoft SQL Server”作为数据源,然后单击“Continue”以建立连接。

使用“Connection Properties”向导窗口连接到“AlwaysEncryption”数据库。快速进行一次“Test Connection”以成功,然后单击“OK”继续。

在下一个向导屏幕中,选择“Yes”单选按钮以将敏感的 SQL 凭据信息存储在连接字符串中。然后提供上下文名称“AlwaysEncryptionContext”,该名称应直接放入web.config文件中的连接字符串属性。

单击“Next”以选择应用程序的 Entity Framework 版本。在本例中,我选择了 EF 6.x 选项。

单击“Next”以选择我们的“Customer”表,并命名 Model Namespace,然后单击“Finish”导入实体模型。

Visual Studio 2015 在实际运行 Text Template (T4) 文件之前会显示几个安全警告对话框。单击“OK”以生成上下文以及实体模型类。

导入后,我们的解决方案如下所示。

使用 Entity Framework 脚手架控制器及视图

现在,右键单击Controller文件夹,然后添加“New Scaffolding Item…”以创建带有 Entity Framework 的 MVC 5 Controller 以及视图。

警告:导入数据库中的实体模型后,始终先生成应用程序,然后再脚手架控制器或视图。

选择“Customer”模型类和“AlwaysEncryptionContext”作为数据上下文类,并将新控制器命名为“CustomersController”。单击“Add”以创建控制器以及执行所有 CRUD 操作的视图。

脚手架控制器及其相应的CRUD视图后,我们的解决方案看起来如下:

现在,在路由配置文件中设置默认控制器和操作,指向我们的新 Customers 控制器和 Index 操作方法。

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Customers", action = "Index", id = UrlParameter.Optional }
);

继续运行应用程序,以填充 Customer 表中的一些记录。

现在转到 **SQL Server Management Studio**,并运行以下查询以列出所有 Customer 记录。这将以纯文本形式显示所有数据。

使用 SQL Server 2016 中的 Always Encrypted 功能加密敏感数据

要在 Microsoft SQL 2016 中加密敏感数据,请右键单击“Customer”表,然后从上下文菜单中选择“Encrypt Columns…”。

这将显示带有“Introduction”屏幕的 **Always Encrypted** 向导,单击“Next”。

现在我们进入“Column Selection”向导屏幕,在这里我们选择要加密的选定表中的所有数据列。

在这里,我们选择了 EmailSSN 列进行加密。请注意,“Encryption Type”列设置为“Deterministic”,并选择默认或自动生成的Column Encryption Key (CEK)

选择确定性或随机加密类型

Always Encrypted 支持两种类型的加密:**确定性加密**和 **随机加密**。

**确定性**加密使用一种方法,该方法对于任何给定的明文值总是生成相同的加密值。使用确定性加密允许基于加密值进行分组、相等性过滤以及表联接,但也可以让未经授权的用户通过检查加密列中的模式来猜测加密值的信息。当加密值的可能集合很小时(例如 True/False,或 North/South/East/West 区域),这种弱点会增加。确定性加密必须为字符列使用具有 binary2 排序顺序的列排序规则。

**随机**加密使用一种以不太可预测的方式加密数据的方法。随机加密更安全,但阻止对加密列进行相等性搜索、分组、索引和联接

对将用作搜索或分组参数的列(例如身份证号码)使用确定性加密。对不与其他记录分组且不用于联接表的机密调查评论等数据使用随机加密。

选择具有所需加密类型的列后,单击“Next”,这将显示“Master Key Configuration”向导屏幕。为了使用 CEK 加密列,我们需要一个**Master Encryption Key (MEK)**,该密钥存储在数据库外部,要么在**Windows Certificate store**中,要么在**Azure key vault**中。

在这里,我们自动生成 MEK,并选择将其存储在**Current User**下的**Windows certificate store**中。

单击 Next 查看“Run Settings”向导。此屏幕警告用户,在加密和解密过程中不要对表执行任何读/写操作。这可能导致潜在的数据丢失。SQL Server 2016 建议在计划的维护窗口中运行此设置。

点击“Next”查看“Summary”向导屏幕。在验证设置后单击“Finish”。

这将显示带有详细信息的“Results”向导屏幕。在我们的情况下,它通过了所有三个步骤:

  1. 在 Windows 证书中生成了一个新的 Column Master Key (CMK)。
  2. 生成了新的 Column Encryption Key (CEK),并且
  3. 在 `Customer` 表上对选定的列执行了加密操作。

现在,再次运行 select 脚本以查看选定的列已被加密。**很棒,不是吗?!**

加密表中的列肯定会改变表架构,但与我们预期的不同。列数据类型不会改变。如果您仔细查看表创建脚本,可以看到 **COLLATE** 以及 **ENCRYPTED WITH CEK** 和 **ALGORITHM**。

注意:截至目前,SQL Server 2016 仅提供一种加密算法“AEAD_AES_256_CBC_HMAC_SHA_256”。

在 ASP.NET MVC 应用程序中进行必要的更改以自动加密/解密数据

现在,重新运行我们的 MVC 应用程序,以查看加密数据如何在我们的视图中显示。奇怪的是,它显示了以下错误消息。应用程序在 Email 列中期望字符串数据类型,但它接收到了加密数据流作为字节数组。

要解决此问题,我们需要更新连接字符串以启用**“column encryption settings”**。这将允许我们的应用程序在连接到数据库时自动加密/解密必要的列。

column encryption setting=enabled

更新后,我们的连接字符串看起来如下:

现在再次运行应用程序,以查看列已自动解密/加密。应用程序利用 MEK 和 CEK 来解密/加密列。

如果您仔细查看数据库安全性下的“Always Encrypted Keys”设置。

右键单击 **CEK** 以生成其创建脚本。

右键单击 **CMK** 以生成创建脚本。在这里,您可以看到 Windows Certificate 的路径。

如果您在 Current User 下查找“Always Encrypted Certificate”。

双击它即可看到证书详情。

假设您备份了数据库,并在另一台机器/服务器上恢复了它。并将 MVC 应用程序指向新数据库… **您认为,如果我们将在另一台机器或服务器上恢复数据库,应用程序会检索到数据吗?**

答案是 **否**。

为什么? 因为,虽然我们可以从备份文件中恢复数据库并拥有所有 CEK 来加密/解密列,但我们没有存储在 Windows 证书存储外部的主加密密钥。并且要获取 MEK 证书,我们需要联系所有者。

这样做时我们会收到错误,因为应用程序无法使用提供的密钥解密/加密列。

查看我关于如何从/到 Windows 证书存储导出和/或导入 Master Encryption Key 的其他文章(待发布)。

单击此处 了解更多关于 SQL Server 2016 中的 "Always Encrypted" 功能

希望您度过了愉快地学习新事物的时光。如果您有任何建议或改进,请告诉我。

随意为本文评分、添加书签并发表评论以获得更好的澄清。

历史

  • 2016 年 7 月 6 日:初始版本
© . All rights reserved.