SQL SERVER:BCP 使用数据库密钥导入和加密列
SQLSERVER: BCP import and encrypt columns using Database Key
我有一个大文件需要导入到 SQL 服务器。文件包含个人信息列(如 first_name、phone_number)。目前我正在使用 BCP 工具将大文件导入 SQL 服务器。下一步,我将使用数据库密钥对列进行加密,如下所示。
CREATE TABLE users (
first_name VARCHAR(4000)
)
CREATE CERTIFICATE db_cert1
WITH SUBJECT = 'Encrypt PII data';
GO
CREATE SYMMETRIC KEY db_symkey1
WITH ALGORITHM = AES_256
ENCRYPTION BY CERTIFICATE db_cert1;
GO
BEGIN TRY
UPDATE users
SET first_name = CAST(EncryptByKey(KEY_GUID('db_symkey1'),[first_name]) AS VARCHAR(MAX))
END TRY
BEGIN CATCH
DELETE FROM users;
END CATCH
我的 table 中有 100 列和 10 列需要加密的敏感列和数百万行。目前它很慢(由于行数和 VARCHAR(MAX/4000))
有没有更好的方法来实现这个? BCP 是否提供开箱即用的解决方案?
由于您的字段类型,我猜您正在执行转换为 nvarchar(max)
。使用 varbinary
会更好。
函数EncryptByKeyreturns:
varbinary with a maximum size of 8,000 bytes.
因此,以这种格式存储您的数据将消除转换的需要。此外,最好使用 varbinary
长度的精确值。
您可以使用下面的公式来检查 EncryptByKey
将 return 用于特定文本列的最大 varbinary 长度:
60 + max_length - ((max_length + 8) % 16)
我经常使用以下脚本:
SELECT name, 60 + max_length - ((max_length + 8) % 16)
FROM sys.columns
WHERE object_id = OBJECT_ID('dbo.securityUsers')
AND name in ('FirstName', 'LastName', 'Gender', 'Address1', 'Address2', 'City', 'Province', 'Country')
例如,对于 nvarchar(128)
,您将有 varbinary(308)
。你只需要有一些方法来知道当你解密时,再次转换为 nvarchar(128)
。
一般来说,尽量使用尽可能小的精度的类型,并尽量转换到尽可能小的精度。
例如,您可以将这些数据插入缓冲区 table,然后将其加密并记录在目标 table 中(无需转换)。
以下是提高性能所遵循的步骤。
- 为每个敏感数据创建了两列
- first_name_plaintext VARCHAR(256)
- first_name VARBINARY(308)
- 感谢@gotqn
- 添加了一个自动递增的 id 列,在 table 上添加了一个聚集索引(这确保它已经排序)并进行了批量更新(如
WHERE [id] BETWEEN 1 AND 100000
)。
- 每次迭代后提交(以减少事务日志的使用)
- 将数据库恢复模型更改为简单(重要)
- 增加了数据库文件大小
- 如果没有限制,您可以使用 AES_128 加密来创建密钥而不是 AES_256,但我们的安全顾问不允许这样做。
这将 100 万条记录的时间从 3 分钟缩短到 1:17 分钟。
我有一个大文件需要导入到 SQL 服务器。文件包含个人信息列(如 first_name、phone_number)。目前我正在使用 BCP 工具将大文件导入 SQL 服务器。下一步,我将使用数据库密钥对列进行加密,如下所示。
CREATE TABLE users (
first_name VARCHAR(4000)
)
CREATE CERTIFICATE db_cert1
WITH SUBJECT = 'Encrypt PII data';
GO
CREATE SYMMETRIC KEY db_symkey1
WITH ALGORITHM = AES_256
ENCRYPTION BY CERTIFICATE db_cert1;
GO
BEGIN TRY
UPDATE users
SET first_name = CAST(EncryptByKey(KEY_GUID('db_symkey1'),[first_name]) AS VARCHAR(MAX))
END TRY
BEGIN CATCH
DELETE FROM users;
END CATCH
我的 table 中有 100 列和 10 列需要加密的敏感列和数百万行。目前它很慢(由于行数和 VARCHAR(MAX/4000))
有没有更好的方法来实现这个? BCP 是否提供开箱即用的解决方案?
由于您的字段类型,我猜您正在执行转换为 nvarchar(max)
。使用 varbinary
会更好。
函数EncryptByKeyreturns:
varbinary with a maximum size of 8,000 bytes.
因此,以这种格式存储您的数据将消除转换的需要。此外,最好使用 varbinary
长度的精确值。
您可以使用下面的公式来检查 EncryptByKey
将 return 用于特定文本列的最大 varbinary 长度:
60 + max_length - ((max_length + 8) % 16)
我经常使用以下脚本:
SELECT name, 60 + max_length - ((max_length + 8) % 16)
FROM sys.columns
WHERE object_id = OBJECT_ID('dbo.securityUsers')
AND name in ('FirstName', 'LastName', 'Gender', 'Address1', 'Address2', 'City', 'Province', 'Country')
例如,对于 nvarchar(128)
,您将有 varbinary(308)
。你只需要有一些方法来知道当你解密时,再次转换为 nvarchar(128)
。
一般来说,尽量使用尽可能小的精度的类型,并尽量转换到尽可能小的精度。
例如,您可以将这些数据插入缓冲区 table,然后将其加密并记录在目标 table 中(无需转换)。
以下是提高性能所遵循的步骤。
- 为每个敏感数据创建了两列
- first_name_plaintext VARCHAR(256)
- first_name VARBINARY(308)
- 感谢@gotqn
- 添加了一个自动递增的 id 列,在 table 上添加了一个聚集索引(这确保它已经排序)并进行了批量更新(如
WHERE [id] BETWEEN 1 AND 100000
)。 - 每次迭代后提交(以减少事务日志的使用)
- 将数据库恢复模型更改为简单(重要)
- 增加了数据库文件大小
- 如果没有限制,您可以使用 AES_128 加密来创建密钥而不是 AES_256,但我们的安全顾问不允许这样做。
这将 100 万条记录的时间从 3 分钟缩短到 1:17 分钟。