如何把一个有加密数据的数据库迁移到其他服务器上
从SQL Server 2005开始,SQL Server进入了加密数据的功能来数据。下面是一段示例T-SQL代码来展示SQL Server如何保护数据的。
USE [master]
GO
Create database testencryption
go
USE testencryption;
GO
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'First p@55w0Rd'
GO
CREATE CERTIFICATE HumanResources037
WITH SUBJECT = 'Employee Social Security Numbers',
START_DATE = '01/01/2012';;
GO
CREATE SYMMETRIC KEY SSN_Key_01 WITH
KEY_SOURCE = 'shared_secret!',
ALGORITHM = AES_256,
IDENTITY_VALUE = 'Key Identity generation bits. Also a shared secret'
ENCRYPTION BY CERTIFICATE HumanResources037;
GO
Create TABLE TestEncryptionColumn
(NationalIDNumber nvarchar (15),
EncryptedNationalIDNumber varbinary(128));
GO
Insert TestEncryptionColumn values ('12345678',NULL)
Go
-- 加密数据.
OPEN SYMMETRIC KEY SSN_Key_01 DECRYPTION BY CERTIFICATE HumanResources037;
UPDATE TestEncryptionColumn
SET EncryptedNationalIDNumber = EncryptByKey(Key_GUID('SSN_Key_01'),
NationalIDNumber);
GO
-- 验证数据可以被正确解密
OPEN SYMMETRIC KEY SSN_Key_01 DECRYPTION BY CERTIFICATE HumanResources037;
go
SELECT NationalIDNumber, EncryptedNationalIDNumber
AS 'Encrypted ID Number',
CONVERT(nvarchar, DecryptByKey(EncryptedNationalIDNumber))
AS 'Decrypted ID Number'
FROM TestEncryptionColumn;
GO
在这个示例中,我们使用密码来保护database master key,然后用database master key加密证书(其实是加密证书中的私钥),再使用证书来加密对称密钥,最后使用对称密钥来加密数据。这是一个很常见的的加密链条。
你可能会注意到一个有意思的现象:要解密数据数据,你只需要打开对称密钥就可以了,你不需要使用之前设置的密码来打开database master key。那么我们为什么还要设置密码呢?没有密码的保护,数据还是安全的吗?
要理解这个问题,我们先要了解下SQL Server加密系统的层次架构。
从这个架构来看,其实最简单的加密方法是使用密码直接保护对称密钥,然后用对称密钥来加密数据。但是加密提供的保护比较简单,数据容易被攻破。在不考虑性能影响的前提下,我们可以使得加密链条尽可能的长来获得更强的保护。
而service key是由DP API (Data Protection API)来加密。DP API也可以使用两种方法来加密service key: (1)SQL Server启动账户(2)安装SQL Server这台服务器的Machine account。如果使用SQL Server configuration manager来修改启动账号的话,configuration manager会先用老的密码解密service master key,再使用新密码来加密service master key。如果使用service control manager来修改账号的话,就会导致无法使用启动账号密码来解密service master key了。幸运的是,此时还有machine account可以用来解密service master key,所以你加密的数据还是可以被访问。如果一旦machine account也由于某些原因发生了变化,那么整个加密链条就头上就断了,其结构就是所有的加密数据都不能访问。所以我们一直推荐使用configuration manager来修改启动账号。
你可以发现,database master key也有两种方法来保护:(1)密码(2)service master key。上面的示例代码其实就是sysadmin用户直接用service master key打开database master key进而访问数据,所以就不需要密码。有的客户基于安全的考虑会把service master key的保护去除掉,这样sysadmin也无法通过打开service master key的方式来访问数据。要访问数据就一定要知道密码。
要去除service master key的保护,可以运行语句
ALTERMASTERKEYDROPENCRYPTIONBYSERVICEMASTERKEY
我们建议你备份service master key, database master key和证书。备份的重要性你很快就会看到。
-- 备份SMK, DMK and certificates
BACKUP SERVICE MASTER KEY TO FILE = 'c:\backup\exportedServiceMasterkey' ENCRYPTION BY PASSWORD = 'Backup p@55w0Rd'
Go
OPEN MASTER KEY DECRYPTION BY PASSWORD = 'First p@55w0Rd';
BACKUP MASTER KEY TO FILE = 'c:\backup\exportedmasterkey' ENCRYPTION BY PASSWORD = 'Backup p@55w0Rd';
GO
BACKUP CERTIFICATE HumanResources037 TO FILE = 'c:\backup\HumanResources037Certificate' WITH PRIVATE KEY ( FILE = 'c:\backup\CertificatePrivateKey' ,ENCRYPTION BY PASSWORD = 'Backup p@55w0Rd' );
GO
如果我们要把一个有加密数据的数据库迁移到一台新的服务器上,有什么特别的步骤需要做吗?
如果你知道database master key的密码,你什么都不需要做。你只需要在新的服务器上还原数据库,然后使用密码打开database master key:
OPEN MASTER KEY DECRYPTION BY PASSWORD = 'First p@55w0Rd'
然后就可以正常打开迁移后数据库中的加密数据了。
如果你不想每次都用密码打开database master key,你可以使用以下语句,在新服务器上使用service master key来保护database master key:
OPEN MASTER KEY DECRYPTION BY PASSWORD = 'First p@55w0Rd'
ALTER MASTER KEY ADD ENCRYPTION BY SERVICE MASTER KEY
这样sysadmin用户就可以直接使用service master key来打开database master key进而打开对称密钥来访问加密数据,而不需要使用database master key的密码。注意,运行Add encryption语句前是一定要用密码打开database master key的,也就是说你一定要记得住你的密码。
如果Database Master Key密码忘记了怎么办?如何迁移数据库?
如果你从来没有去除过service master key的保护的话,你是很安全的。你只需要用sysadmin登录原服务器的SQL Server再运行一下命令来生成一个新的密码:
Alter Master Key Regenerate With Encryption By Password = 'NewPassword'
然后就可以按照上面的办法来迁移数据库了。
如果在原数据库上你没有去除过service master key的保护,但你又不想在原服务器上生成新密码(可能原服务器是生产环境不能随便动),你可以立刻备份一个service master key或者使用之前创建的service master key的备份,然后在新服务器上依次还原service master key和数据库,同样可以实现迁移的目的。
-- 在新服务器还原service master key
RESTORE SERVICE MASTER KEY FROM FILE = 'c:\exportedServiceMasterkey' DECRYPTION BY PASSWORD = 'Backup <p@55w0Rd'>;
-- 在新服务器还原数据库
然后在新服务器上就可以打开数据并访问了。
OPEN SYMMETRIC KEY SSN_Key_01 DECRYPTION BY CERTIFICATE HumanResources037;
go
SELECT NationalIDNumber, EncryptedNationalIDNumber AS 'Encrypted ID Number',CONVERT(nvarchar, DecryptByKey(EncryptedNationalIDNumber)) AS 'Decrypted ID Number'FROM TestEncryptionColumn;
GO
如果你忘记了Database Master Key密码并且已经去除了service master key的保护,还有可能打开加密数据吗?
有可能,只要你曾经备份过证书,database master key和service master key。你只要还原它们就万事ok了。
-- 假设对称密钥,证书和database master key都没了,service master key也被改掉了。此时加密数据完全打不开。
drop SYMMETRIC KEY SSN_Key_01
drop CERTIFICATE HumanResources037
drop MASTER KEY
ALTER SERVICE MASTER KEY REGENERATE;
GO
-- 依次还原service master key, database master key
RESTORE SERVICE MASTER KEY
FROM FILE = 'c:\backup\exportedServiceMasterkey'
DECRYPTION BY PASSWORD = 'Backup p@55w0Rd';
GO
RESTORE MASTER KEY FROM FILE = 'c:\backup\exportedmasterkey'
DECRYPTION BY PASSWORD = 'Backup p@55w0Rd'
ENCRYPTION BY PASSWORD = 'New p@55w0Rd'
-- 重建证书和对称密钥
OPEN MASTER KEY DECRYPTION BY PASSWORD = 'New p@55w0Rd';
CREATE CERTIFICATE HumanResources037
FROM FILE = 'c:\backup\HumanResources037Certificate'
WITH PRIVATE KEY (FILE = 'c:\backup\CertificatePrivateKey',
DECRYPTION BY PASSWORD = 'Backup p@55w0Rd');
GO
CREATE SYMMETRIC KEY SSN_Key_01 WITH
KEY_SOURCE = 'shared_secret!',
ALGORITHM = AES_256,
IDENTITY_VALUE = 'Key Identity generation bits. Also a shared secret'
ENCRYPTION BY CERTIFICATE HumanResources037;
GO
-- 现在数据又可以打开了
OPEN SYMMETRIC KEY SSN_Key_01 DECRYPTION BY CERTIFICATE HumanResources037;
go
SELECT NationalIDNumber, EncryptedNationalIDNumber
AS 'Encrypted ID Number',
CONVERT(nvarchar, DecryptByKey(EncryptedNationalIDNumber))
AS 'Decrypted ID Number'
FROM TestEncryptionColumn;
GO
CLOSE SYMMETRIC KEY SSN_Key_01
GO
这个例子也适用于证书,database master key和对称密钥被误删的情况。
如果忘记了密码,又去除了service master key的保护,又没有备份service master key ,怎么办?
什么办法也没有。