Always Encrypted
适用于: SQL Server
Azure SQL 数据库
Azure SQL 托管实例
Always Encrypted 功能旨在保护 Azure SQL 数据库、Azure SQL 托管实例和 SQL Server 数据库中存储的敏感数据,如信用卡号或国民/地区身份证号(例如,美国社会安全号码)。 通过 Always Encrypted,客户可在客户端应用程序中加密敏感数据,并且永远不会向数据库引擎透漏加密密钥。 这在拥有并可以查看数据的人员与管理数据但不应具有访问权限的人员(本地数据库管理员、云数据库操作员或其他高特权未经授权的用户)之间实现分隔。 因此,Always Encrypted 让客户能自信地将敏感数据存储在云中,并减少恶意内部人员盗窃数据的可能性。
Always Encrypted 可配置为支持对加密数据的有限机密查询(这些查询涉及相等比较)。 例如,点查找搜索或相等联接。 此类查询利用确定性加密。
注意
安全 Enclave 通过模式匹配、其他比较运算符和就地加密,提升了 Always Encrypted 的机密计算能力。 有关详细信息,请参阅具有安全 enclave 的 Always Encrypted。
始终加密使向加密对应用程序透明。 安装在客户端计算机上的启用始终加密的驱动程序通过在客户端应用程序中对敏感数据进行加密和解密来实现此目标。 该驱动程序先对敏感列中的数据进行加密,然后再将该数据传递到 数据库引擎,并且自动重写查询以便保留应用程序的语义。 同样,该驱动程序透明地解密存储在查询结果中包含的加密数据库列中的数据。
配置 Always Encrypted
本部分概述了如何设置 Always Encrypted。 有关详细信息和入门指南,请参阅教程:Always Encrypted 入门。
若要在数据库中设置 Always Encrypted,则需要:
预配加密密钥以保护数据。 Always Encrypted 使用两种类型的密钥:
- 列加密密钥。
- 列主密钥。
列加密密钥用于对加密列中的数据进行加密。 列主密钥是对一个或多个列加密密钥进行加密的密钥保护密钥。
列主密钥必须存储在数据库系统之外受信任的密钥存储中,例如 Azure 密钥保管库、Windows 证书存储或硬件安全模块。
然后,需要预配列加密密钥,并使用列主密钥对它们进行加密。
最后,需要将有关密钥的元数据存储在数据库中。
- 列主密钥元数据捕获列主密钥的位置。
- 列加密密钥元数据包含列加密密钥的加密值。 数据库引擎不会存储或使用纯文本的任一类型密钥。
有关管理 Always Encrypted 密钥的详细信息,请参阅 Always Encrypted 密钥管理概述。
为包含所要保护的敏感数据的选定数据库列配置加密。 这可以涉及使用加密列创建新表或加密现有数据库列和现有数据。 设置列的加密信息时,将指定加密算法、用于保护列中的数据的列加密密钥,以及加密类型的信息。 Always Encrypted 支持以下两种类型的加密:
对于任何给定的纯文本值,“确定性加密”始终生成相同的加密值。 使用确定性加密允许对加密列进行点查找、等值联结、分组和建立索引。 但也可能允许未经授权的用户通过检查加密列中的模式来猜测有关加密值的信息,尤其是存在一个规模较小的可能加密值集合时,如 True/False 或 North/South/East/West 等区域。
随机加密 使用一种以更不可预测地方式加密数据的方法。 随机加密更加安全,但不支持对加密列进行搜索、分组、索引和联接。
针对要用作搜索参数或分组参数的列使用确定性加密。 例如,政府 ID 号。 针对不会与其他记录分组在一起且不会用来联接表的数据(例如机密的调查注解)使用随机加密。
有关 Always Encrypted 加密算法的详细信息,请参阅 Always Encrypted 加密。
可以使用 SQL 工具执行上述步骤:
- SQL Server Management Studio (SSMS)
- SQL Server PowerShell
- sqlpackage - 自动执行安装过程
为确保始终不向数据库环境公开纯文本形式的 Always Encrypted 密钥和受保护敏感数据,因此数据库引擎不会参与密钥预配,也不会执行数据加密或解密操作。 因此,Transact-SQL (T-SQL) 不支持密钥预配或加密操作。 由于同样原因,加密现有数据或重新加密它(使用不同的加密类型或列加密密钥)需要在数据库外部执行(SQL 工具可以自动执行)。
注意
具有安全 enclave 的 Always Encrypted 通过允许使用 T-SQL 对现有数据执行加密操作,消除了在数据库外部移动数据的需求,从而消除了上述一些限制。
如何对加密列运行查询
若要对加密的数据库列运行查询、将数据插入加密列、从加密列检索纯文本值,或者使用确定性加密对列执行受支持的操作(例如,点查找搜索),发出查询的用户或应用程序必须满足以下先决条件:
- 有权访问保护数据的列主密钥。 除了数据库级权限之外,还需要进行密钥访问,例如对包含数据的表进行
SELECT
。 - 连接到数据库,同时在数据库连接中启用 Always Encrypted。 大多数 SQL 工具和 SQL 客户端驱动程序都支持为数据库连接启用 Always Encrypted。
注意
如果用户具有读取数据所需的数据库权限,但无法访问保护数据的密钥,则用户仍可以通过连接到数据库来检索 cyphertext (加密) 数据,而无需在数据库连接中启用 Always Encrypted。
下面是对加密列进行查询的工作原理:
- 当应用程序发出参数化查询时,应用程序中的 SQL 客户端驱动程序以透明方式联系数据库引擎(通过调用 sp_describe_parameter_encryption (Transact-SQL) 来确定哪些参数以加密列为目标,并应加密。 对于需要加密的每个参数,驱动程序将接收加密算法、加密类型和密钥元数据,包括加密列加密密钥及其相应列主密钥的位置。
- 驱动程序会调用包含列主密钥的密钥存储,以解密加密列的加密密钥值。 产生的纯文本列加密密钥已缓存,以便在以后使用相同的列加密密钥时减少对密钥存储的往返访问次数。
- 驱动程序使用获取的纯文本列加密密钥来加密对应加密列的查询参数。
- 驱动程序将指向加密列的参数的纯文本值替换为它们的加密值,并将查询发送到数据库引擎以进行处理。
- 数据库引擎执行查询,这可能涉及使用确定性加密对列进行相等比较。
- 如果查询结果包括来自加密列的数据,则数据库引擎会将每个列的加密元数据附加到结果集中,其中包括有关加密算法、加密类型和密钥元数据的信息。
- 数据库引擎将结果集发送到客户端应用程序。
- 对于接收的结果集中的每个加密列,驱动程序首先尝试在本地缓存中查找纯文本列加密密钥,如果无法在缓存中找到该密钥,则只访问持有列主密钥的密钥存储库。
- 驱动程序解密结果并将纯文本值返回给应用程序。
客户端驱动程序使用列主密钥存储提供程序与包含列主密钥的密钥存储进行交互,列主密钥存储提供程序是一个客户端软件组件,用于封装包含列主密钥的密钥存储。 常见类型的密钥存储的提供程序在 Microsoft 的客户端驱动程序库中提供,或作为单独的软件下载。 你也可以实现自己的提供程序。 Always Encrypted 功能(包括内置的列主密钥存储提供程序)因驱动程序库及其版本而异。
有关支持 Always Encrypted 的客户端驱动程序列表以及有关如何开发查询加密列的应用程序的信息,请参阅使用 Always Encrypted 开发应用程序。
还可以使用 SQL 工具(例如 Azure Data Studio 或 SSMS)查询加密列。
限制
对加密列的查询存在以下限制:
确定性加密支持以下涉及相等比较的操作 - 不允许其他操作。
- 点查找搜索中的= (Equals)。
- IN。
- SELECT - GROUP BY。
- DISTINCT。
不允许对使用随机加密进行加密的列进行计算。
注意
具有安全 Enclave 的 Always Encrypted 通过启用模式匹配、比较运算符、分类和对使用随机加密的列编制索引来解决上述限制。
不允许触发涉及纯文本和加密数据的计算的查询语句。 例如:
- 将加密列与纯文本列或文本进行比较。
- 使用 UPDATE、BULK INSERT、SELECT INTO 或 INSERT..SELECT 将数据从纯文本列复制到加密列(或以其他方式)。
- 将文本插入加密列。
此类语句会导致操作数冲突错误,如下所示:
Msg 206, Level 16, State 2, Line 89 Operand type clash: char(11) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_1', column_encryption_key_database_name = 'ssn') collation_name = 'Latin1_General_BIN2' is incompatible with char
应用程序必须使用查询参数传递与加密列对应的值。 例如,将数据插入加密列或按加密列进行筛选时(使用确定性加密时)。 不支持传递对应加密列的文本或 T-SQL 变量。 有关特定于使用的客户端驱动程序的详细信息,请参阅使用 Always Encrypted 开发应用程序。
必须为 Azure Data Studio 或 SSMS 中的 Always Encrypted 变量使用参数化来发出查询,这些查询传递与这些工具中的加密列相对应的值。 例如,将数据插入加密列或按加密列进行筛选时(使用确定性加密时)。
不支持针对加密列的表值参数。
不支持使用下列子句的查询:
更改加密列的定义之后,需执行 sp_refresh_parameter_encryption,以更新该对象的 Always Encrypted 元数据。
具有以下特征的列不支持 Always Encrypted:
- 使用以下任一数据类型的列:xml、timestamp、rowversion、image、ntext、text、sql_variant、hierarchyid、geography、geometry、别名、用户定义类型。
- FILESTREAM 列
- 具有 IDENTITY 属性的列。
- 具有 ROWGUIDCOL 属性的列。
- 使用确定性加密时,除二进制码位 (_BIN2) 排序规则以外的排序规则的字符串(varchar、char 等)列。
- 使用随机加密时用作聚集索引和非聚集索引的键的列(支持使用确定性加密在列上添加索引)。
- 全文检索中包含的列(Always Encrypted 不支持全文搜索)。
- 计算列。
- 计算列引用的列(当表达式针对 Always Encrypted 执行不受支持的操作时)。
- 稀疏列集。
- 使用随机加密时统计信息引用的列(支持确定性加密)。
- 分区列。
- 包含默认约束的列。
- 使用随机加密时 unique 约束引用的列(支持确定性加密)。
- 使用随机加密时的主键列(支持确定性加密)。
- 使用随机加密或确定性加密时引用外键约束中的列(如果被引用和引用列使用不同的键或算法)。
- check 约束引用的列。
- 使用更改数据捕获捕获/跟踪的列。
- 具有更改跟踪的表中的主键列。
- 屏蔽的列(使用动态数据掩码)。
- 延伸数据库表中的列。 (无法为延伸启用其列已使用始终加密加密的表。)
重要
SQL Server 2022 (16.x) 和 Azure SQL 数据库中已弃用 Stretch Database。 在数据库引擎的未来版本中将删除此功能。 请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。
- 外部 (PolyBase) 表中的列(注意:支持在同一查询中使用外部表和列已加密的表)。
以下功能对加密的列不起作用:
- SQL Server 复制(事务性复制、合并复制或快照复制)。 支持物理复制功能,包括 Always。
- 分布式查询(链接服务器、OPENROWSET (Transact-SQL)、OPENDATASOURCE (T-SQL))。
- 跨数据库查询,这些查询对不同数据库的列执行联接(使用确定性加密)。
Always Encrypted Transact-SQL 参考
Always Encrypted 使用以下 Transact-SQL 语句、系统目录视图、系统存储过程和权限。
语句
- CREATE COLUMN MASTER KEY (Transact-SQL)
- DROP COLUMN MASTER KEY (Transact-SQL)
- CREATE COLUMN ENCRYPTION KEY (Transact-SQL)
- ALTER COLUMN ENCRYPTION KEY (Transact-SQL)
- DROP COLUMN ENCRYPTION KEY (Transact-SQL)
- CREATE TABLE (ENCRYPTED WITH)
系统目录视图和存储过程
- sys.column_encryption_keys (Transact-SQL)
- sys.column_encryption_key_values (Transact-SQL)
- sys.column_master_keys (Transact-SQL)
- sp_refresh_parameter_encryption (Transact-SQL)
- sp_describe_parameter_encryption (Transact-SQL)
另请参阅 sys.columns (Transact-SQL),以便了解有关为每个列存储的加密元数据的信息。
数据库权限
“始终加密”功能需要有四个数据库权限:
更改任意列主密钥 - 在创建和删除列主密钥元数据时需要。
更改任意列加密密钥 - 在创建和删除列加密密钥元数据时需要。
查看任意列主密钥定义 - 在访问和读取列主密钥的元数据(查询加密列所需)时需要。
查看任意列加密密钥定义 - 在访问和读取列主密钥的元数据(查询加密列所需)时需要。
下表总结了常见的操作所需的权限。
场景 | ALTER ANY COLUMN MASTER KEY | ALTER ANY COLUMN ENCRYPTION KEY | VIEW ANY COLUMN MASTER KEY DEFINITION | VIEW ANY COLUMN ENCRYPTION KEY DEFINITION |
---|---|---|---|---|
密钥管理(创建/更改/检查数据库中的密钥元数据) | X | X | X | X |
查询加密列 | X | X |
重要注意事项
即使用户无权访问列主密钥(在其密钥存储中)和保护列,并且不访问纯文本尝试,选择加密列时也需要“查看任意列主密钥定义”和“查看任意列加密密钥定义”权限。
在 SQL Server 中,默认授予 public 固定数据库角色“查看任意列主密钥定义”和“查看任意列加密密钥定义”权限。 数据库管理员可以选择撤销(或拒绝)public 角色的权限,并将该权限授予特定的角色或用户来实现更严格的控制。
在 SQL 数据库中,默认授予 public 固定数据库角色“查看任意列主密钥定义”和“查看任意列加密密钥定义”权限。 这可以使某些现有的旧工具(使用旧版本的 DacFx)能够正常工作。 要使用加密列(即使不对其进行解密),数据库管理员必须显式授予“查看任意列主密钥定义”和“查看任意列加密密钥定义”权限。