SQL Server Encryption for Express or Standard
Security is the game that needs to be played to make management think they are taking adequate steps to safe guard data. Ask Sony if this appropriate.
I've recently been asked to provide encryption for a sql server express database implementation. There is much written about sql server's encryption features, but you don't see many details about how to do it for real in an application. Of course the standard replies about Tabular Data Encryption (TDE) are not available in any edition of SQL Server, except enterprise, so this methodology I am laying out here works for Express, Standard or Work Group.
The goal was to provide a standard guidance for developing applications that require encryption, and also it should work for legacy applications with as few changes as possible (Oh, that's a beauty).
What I came up with was an encryption architecture that pulls from things I learned from: - Protegrity (a security vendor, appliance) - Expert SQL Server 2008 Encryption by Michael Coles and J. Luetkehoelter - Database Encryption and Key Management for Microsoft SQL Server 2008: Understanding cell-level encryption and Transparent Data Encryption in Microsoft by Rob Walters and Christian Kirsch
[Damn, now that's a title for a book, they should have chosen "The Rats of SQL" or something just to make it interesting!]
Here it is, comments and suggestions are welcomed as often there are just too many bull shit blog posts on encryption; giving simple regurgitated examples from books on line. That's crap, working with encryption for real in your application does not need to be nightmare, you do not need to fork over 20K+ a socket for enterprise edition [well, you might!!], you do not need to re-write your whole application, performance may suck, but that's not the point of this guidance.... -----------------------
Encryption is bad, but so is Cicada flavored ice cream.
------------------------
SQL Server Express Database Encryption
The goal of encrypting data in the database engine is to protect data at rest (including backups) at the column (cell) level. It does not protect data during transit over the network or from users who have the appropriate permissions and/or passwords.
The approach outlined here is only for the field database engine, it is targeted for SQL Server Express 2008, small databases with limited number of users; this solution is not designed for highly scalable OLTP databases.
The goal of the encryption process is to abstract the tables with cell level encryption by over-laying them with views. This allows the application (with the proper permissions) to continue to work with the encrypted data seamlessly via the normal development methodologies without having to consistently write the code to decrypt / encrypt the columns (cells). This process is the generally the same for new applications and existing applications that need to be modified to encrypt data with the key difference being the requirement to open the keys for new applications to provide additional security.
The SQL Server encryption functions return varbinary data, so all columns to be encrypted need to be changed to varbinary. The use of Views to over-lay the tables provides an abstraction layer so the data types can be properly viewed for data modelers, developers, administrators, analysts and other end users. To encrypt a SSN, varchar(9) field requires the column in the base table to be implemented as varbinary(200). The data modeling group creates a logical model subject area in Erwin that uses the views and other non-encrypted tables to create a data model that is useable (not displaying varbinary as the data type for encrypted fields, but their actual un-encrypted data type).
Users that access the views, who do not have permissions to open the proper key(s) will not receive an error, but the column will not be decrypted and will be populated with nulls.
Database developers will need to work closely with the data modeling team and the administrators to ensure the data types, views, encryption keys, backup and restore of keys are implemented properly. Data is not recoverable if the backup of keys and databases are not implemented properly.
Guidelines for implementing cell level encryption.
All tables that include an encrypted cell (column) follow the normal standard naming conventions with the addition of an underscore and the word base to the table name {tablename}_base. All columns follow the standard implementation with the exception of those to be encrypted, which must use a varbinary data type. The length of the varbinary column is determined by the max length returned from the encryption function. Please work the data modeler and the administrators to determine the proper length based on the requirements for each column.
A view is created that follows the normal standards, except the name is implemented off the base table by dropping the underscore and the word base that was used to name the table (this allows legacy code to continue to work). The view will make use of the decryption function and the proper Cast and Convert statements to manipulate the varbinary column to the correct un-encrypted data type.
Inserts, updates and deletes are handled in the normal manner, with the tsql statements being executed against the view, NOT the underlying tables. “Instead of Triggers” are created on each view to handle the Inserts, updates and deletes. This provides an additional layer of abstraction so that consistency can be maintained with the code.
All data access should continue according to the published standards (generally this is through stored procedures), refer to the Database governance document for details.
The ability to truncate a table is not available on views (by design), or on base tables according to our standard development methodologies, use the stored procedure truncate_tbl, the procedure will determine if it is a view and truncate the underlying table.
Text and Blob columns are not explicitely covered by this guidance, blob and text columns must be encrypted using CLR functions or by the application. A more detailed example encrypting blobs will be published later. (Be especially careful of free form text columns, end users often put PII data elements in these, thus requiring them to be encrypted).
A short tsql script example:
Create database encrypt_test;
go
use encrypt_test;
go
Create master key encryption by password = 'knights12$gzmlauncher#1@%dmissionisclear*()'
go
create certificate cert_sk with subject = 'Certificate for accessing symmteric keys - for use by App'
go
CREATE SYMMETRIC KEY sk_encrypt_test WITH ALGORITHM = AES_256 ENCRYPTION BY CERTIFICATE cert_sk
go
ALTER MASTER KEY DROP ENCRYPTION BY SERVICE MASTER KEY;
go
create table dbo.Client_Base
( client_Id int Identity(1,1) primary key,
ssn varbinary(200),
Amount_due varbinary(200),
Comments varchar(1000)
);
go
create view dbo.Client
as
Select Client_ID,
convert(varchar(9),decryptbykeyautocert(cert_id('cert_sk'),
Null,SSN,1,convert(varchar(10),client_Id))) AS SSN,
convert(money,convert(varchar(10),decryptbykeyautocert(cert_id('cert_sk'),
Null,Amount_Due,1,convert(varchar(10),client_Id)))) AS Amount_Due,
Comments
From dbo.Client_Base;
go
select * from dbo.client;
go
create trigger dbo.trg_client_insert
on dbo.Client
INSTEAD OF INSERT
AS
BEGIN
Declare @Client_ID int, @SSN varchar(9), @Amount_Due money,
@Comments varchar(1000);
open SYMMETRIC key sk_encrypt_test decryption by certificate cert_sk;
DECLARE cur_Client CURSOR FOR
SELECT SSN,Amount_Due,Comments FROM INSERTED;
OPEN cur_Client;
FETCH NEXT FROM cur_Client INTO @SSN, @Amount_Due,@Comments;
WHILE @@FETCH_STATUS = 0
BEGIN
Insert into dbo.Client_Base (Comments) values (@Comments)
set @Client_Id = scope_identity()
Update dbo.Client_base
set SSN = encryptbykey(key_guid('sk_encrypt_test'),@SSN,1,Convert(varchar(10),@Client_ID))
,Amount_Due = encryptbykey(key_guid('sk_encrypt_test'),convert(varchar(10),@Amount_Due),1,Convert(varchar(10),Client_ID))
where Client_ID = @Client_ID
FETCH NEXT FROM cur_Client INTO @SSN, @Amount_Due,@Comments
END
CLOSE cur_Client
DEALLOCATE cur_Client
CLOSE SYMMETRIC key sk_encrypt_test
END
go
create TRIGGER trg_Client_Update ON dbo.Client
INSTEAD OF UPDATE
AS
BEGIN
open SYMMETRIC key sk_encrypt_test decryption by certificate cert_sk
Update Client_base
Set SSN = encryptbykey(key_guid('sk_encrypt_test'),i.SSN,1,Convert(varchar(10),i.Client_ID))
,Amount_Due = encryptbykey(key_guid('sk_encrypt_test'),convert(varchar(10),i.Amount_Due),1,Convert(varchar(10),i.Client_ID))
FROM Client_Base
inner join inserted i on Client_Base.Client_ID = i.Client_Id
CLOSE SYMMETRIC key sk_encrypt_test
END
go
create trigger dbo.trg_Client_Delete
on dbo.Client
INSTEAD OF DELETE
AS
BEGIN
Delete Client_Base
from Client_Base db
inner join deleted d on db.Client_ID = d.Client_ID
END
go
-- Stored procedures are written as normal
Create procedure dbo.usp_Client_get_by_SSN
@ssn varchar(9)
As
begin
Select * from Client
where ssn = @ssn
end
----------------------------------------------------------
-- MUST OPEN KEY or all insert statements will FAIL
OPEN MASTER KEY
DECRYPTION BY PASSWORD = N'knights12$gzmlauncher#1@%dmissionisclear*()';
GO
Insert into dbo.client (ssn,amount_due,comments) values
('123456789',256.01,'This is a test of encryption')
go
select * from dbo.client;
select * from dbo.client_base;
go
Update Client
set ssn = 987654321,
Amount_Due = 100
where ssn = 123456789;
go
select * from Client;
go
Close Master Key;
-- stored procedures work normally, though no data if key is not open
exec dbo.usp_Client_get_by_ssn @SSN = 987654321
-- now open key and data is returned.
OPEN MASTER KEY
DECRYPTION BY PASSWORD = N'knights12$gzmlauncher#1@%dmissionisclear*()';
GO
exec dbo.usp_Client_get_by_ssn @SSN = 987654321;
go
delete from client where SSN = 987654321
go
select * from Client;
go
|