使用SQL Server 2016的Always Encrypted特性保护敏感数据

在当今这个数据泄露事件频发的时代,保护敏感数据的安全变得尤为重要。SQL Server 2016引入了一个名为"Always Encrypted"的新特性,它允许客户端应用程序对敏感数据进行加密,而数据库引擎(SQL Database或SQL Server)则永远不会接触到加密密钥。这样,"Always Encrypted"提供了数据拥有者(可以查看数据)和数据管理者(但不应访问数据)之间的分离。

创建数据库表并连接到ASP.NET MVC应用程序

首先,需要创建一个新的数据库"AlwaysEncryption",并在其中创建一个名为"Customer"的表,假设"Email"和"SSN"列包含敏感信息。接下来,将创建一个新的ASP.NET Web应用程序"AlwaysEncryption"。在这个示例中,将使用Visual Studio 2015。

选择MVC作为新ASP.NET项目模板,由于不关注认证,点击“更改认证”按钮选择“无认证”选项,然后点击“确定”。

接下来,将向"Models"文件夹添加一个新的实体数据模型文件。从“实体数据模型”向导中选择“从数据库生成EF设计器”,然后点击“下一步”。

在下一个向导屏幕中,选择“Microsoft SQL Server”作为数据源,然后点击“继续”以建立连接。使用“连接属性”向导窗口连接到“AlwaysEncryption”数据库。进行快速的“测试连接”,成功后点击“确定”继续。

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

点击“下一步”选择应用程序的Entity Framework版本。在例子中,选择了EF 6.x选项。

点击“下一步”选择“Customer”表,并命名模型命名空间,然后点击“完成”以导入实体模型。

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

使用Entity Framework生成控制器和视图

现在右键点击"Controller"文件夹,添加“新建脚手架项...”以使用Entity Framework创建MVC 5控制器以及视图。

警告:在从数据库导入实体模型后,首先构建应用程序,然后再创建控制器或视图。

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

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

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

运行应用程序以在Customer表中填充一些记录。然后转到SQL ServerManagement Studio并运行以下查询以列出所有Customer记录。这将以明文形式显示所有数据。

使用SQL Server2016的Always Encrypted特性加密敏感数据

要使用Microsoft SQL 2016加密敏感数据,请右键点击“Customer”表,从上下文菜单中选择“加密列...”。

这将显示“Always Encrypted”向导的“介绍”屏幕,点击“下一步”。

现在得到了“列选择”向导屏幕,这是选择需要加密的选定表中的数据列的地方。在这里,选择了"Email"和"SSN"列进行加密。注意“加密类型”列设置为“确定性”,并选择了默认或自动生成的列加密密钥(CEK)。

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

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

随机加密使用一种方法,以不太可预测的方式加密数据。随机加密更安全,但阻止了基于加密列的等值搜索、分组、索引和连接。

对于将用作搜索或分组参数的列,例如政府ID号,使用确定性加密。对于数据如机密调查评论,不与其他记录分组,并且不用于连接表,请使用随机加密。

在选择具有所需加密类型的列后,点击“下一步”,这将显示“主密钥配置”向导屏幕。为了使用CEK加密列,需要一个主加密密钥(MEK),它存储在数据库外部,可以是Windows证书存储或Azure密钥库。

在这里,自动生成MEK并选择将其存储在“当前用户”下的Windows证书存储中。点击下一步以查看“运行设置”向导屏幕。这个屏幕警告用户不要在加密和解密过程中对表执行任何读写操作。这可能导致潜在的数据丢失。SQL Server 2016建议在计划的维护窗口期间运行此设置。

点击“下一步”以查看“摘要”向导屏幕。在验证设置后点击“完成”。

这将显示“结果”向导屏幕,其中显示了详细信息。在案例中,它通过了所有三个步骤:在Windows证书中生成了一个新的列主密钥CMK,生成了新的列加密密钥CEK,并在Customer表上执行了所选列的加密操作。

现在再次运行选择脚本,以查看所选列已加密。

完美,不是吗?!在表中加密列肯定会改变表模式,但并不像所有人预期的那样。列数据类型不会有任何变化。如果仔细查看表创建脚本,可以看到带有CEK的ENCRYPTED WITH和ALGORITHM。

注意:截至目前,SQL Server2016只提供了一种加密算法“AEAD_AES_256_CBC_HMAC_SHA_256”。

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

为了解决这个问题,需要更新连接字符串以启用“列加密设置”。这将允许应用程序在连接到数据库时自动加密/解密必要的列。

column encryption setting=enabled

这是更新后的连接字符串的样子。

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

如果仔细看数据库安全性下的"Always Encrypted Keys"设置:右键点击CEK以生成其创建脚本:右键点击CMK以生成创建脚本。在这里,可以看到Windows证书的路径:

如果去查找“当前用户”下的"Always Encrypted Certificate"...这里是双击时的证书详细信息。

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

答案是不。为什么?因为,尽管可能从备份文件中恢复了数据库并可以访问所有CEK以加密/解密列,但没有存储在Windows证书存储中的主加密密钥。要获取MEK证书,需要联系所有者。

这样做时,应用程序将无法使用提供的密钥解密/加密列,并会出现错误。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485