Y a-t-il un moyen rapide de trouver toutes les colonnes de SQL Server 2008 R2 qui sont cryptées/ont des données cryptées?
J'ai besoin d'annuler les données dans toutes les colonnes cryptées d'un serveur de développement (selon nos règles métier). Je connais la plupart des colonnes parce que nous les utilisons régulièrement, mais je veux être minutieux et que je veux aussi pouvoir prouver que je les ai tous trouvés.
J'ai cherché le web, regardé in informations_schema et vérifié les DMV que je pensais être utile et aussi Sys.Columns et Sys.Objects - - Mais jusqu'à présent pas de chance.
En supposant que vous parlez de données cryptées avec les clés SQL Server, il existe un moyen de trouver ces colonnes.
La fonction Key_name()
Retournera le nom de la clé utilisée pour le cryptage pour cette valeur particulière et retournera null s'il n'y a rien de crypté avec une clé "connue" (3ème partie ou simple non cryptée) .
Avec ce klighlegde, nous pouvons tester chaque colonne pour voir s'il contient au moins une ligne qui a une valeur variée qui renvoie un nom de clé
fonctionnalité de Key_Name ()
--create a test database
CREATE DATABASE [Test_ENCR]
GO
--change context
USE [Test_ENCR]
GO
--because it's possible to encrypt different rows with different keys I'll create 2 keys for this demo
-- Create a symmetric key
CREATE SYMMETRIC KEY symmetricKey1
WITH ALGORITHM = AES_128
ENCRYPTION BY PASSWORD = 'password01!';
GO
-- Create a second key
CREATE SYMMETRIC KEY symmetricKey2
WITH ALGORITHM = AES_128
ENCRYPTION BY PASSWORD = 'password02!';
GO
--create a table that will have a column holding:
--1: encrypted row with key1
--2: encrypted row with key2
--3: a non encrypted just varbinary value
CREATE TABLE encryptedTable
(ID int IDENTITY PRIMARY KEY,
EncryptedCol varbinary(256) NOT NULL);
GO
-- open key1
OPEN SYMMETRIC KEY symmetricKey1
DECRYPTION BY PASSWORD = 'password01!';
GO
-- open key2
OPEN SYMMETRIC KEY symmetricKey2
DECRYPTION BY PASSWORD = 'password02!';
GO
--insert encrypted data with key1
INSERT INTO encryptedTable(encryptedCol)
VALUES ( ENCRYPTBYKEY (Key_GUID('symmetricKey1'), 'EncryptedText1'));
GO
--insert encrypted data with key2
INSERT INTO encryptedTable(encryptedCol)
VALUES ( ENCRYPTBYKEY (Key_GUID('symmetricKey2'), 'EncryptedText2'));
GO
--insert just varbinary data
INSERT INTO encryptedTable(encryptedCol)
VALUES (CONVERT(varbinary(256),'NotEncryptedTextJustVarBinary'))
--have a look, without the key, all varbinary for you.
SELECT * FROM encryptedTable
GO
résultats:
--Return all key_names
SELECT DISTINCT key_name(encryptedcol),
EncryptedCol
FROM encryptedTable;
résultats:
Comment la mettre en œuvre pour trouver des colonnes cryptées
--How do we dynamically find all the columns that have at least one row with a encrypted value?
-- first we will find all tables and column with a varbinary datatype
-- then we will test all those columns with a simple select
-- If the key_name() function returns a value, the column and table name are stored together with the keyname
--create a table to hold all varbinary columns and tables
CREATE TABLE #TablesWithVarbinCols ( ID int IDENTITY,
TableName nvarchar(128),
ColumnName nvarchar(128)
);
--create a table to hold the end result
CREATE TABLE #TablesWithEncryption (
TableName nvarchar(128),
ColumnName nvarchar(128),
KeyName varchar(128)
);
--find and store all table and column names of user tables containing a varbinary column
INSERT INTO #TablesWithVarbinCols (TableName,ColumnName)
SELECT o.[name] as TableName,
c.[name] as ColumnName
FROM sys.objects o
INNER JOIN sys.columns c
ON o.[object_id]=c.[object_id]
INNER JOIN sys.types t
ON c.system_type_id=t.system_type_id
WHERE o.[type]='U'
AND t.name=N'varbinary'
AND c.max_length > -1;
DECLARE @col nvarchar(256)
DECLARE @tab nvarchar(256)
DECLARE @c int = 1
DECLARE @MaxC int
DECLARE @SQL varchar(max)
SELECT @MaxC=MAX(ID)
FROM #TablesWithVarbinCols
--loop the previous result and create a simple select statement with a key_name() is not null where clause.
--If you have a result, store the details
WHILE @c <= @MaxC
BEGIN
SELECT @Tab=TableName,
@col=ColumnName
FROM #TablesWithVarbinCols
WHERE ID=@c
SET @SQL=' INSERT INTO #TablesWithEncryption (TableName, ColumnName, KeyName)
SELECT DISTINCT '''+@Tab +''',''' +@col +''', key_name('+@Col +') from '+ @tab +'
WHERE key_name('+@Col +') is not null;'
exec (@SQL)
DELETE
FROM #TablesWithVarbinCols
WHERE id=@c;
SET @c=@c+1
END
--select the result
SELECT * FROM #TablesWithEncryption;
résultats:
--cleanup
DROP TABLE #TablesWithVarbinCols;
DROP TABLE #TablesWithEncryption;
Le problème avec le cryptage de niveau cellulaire est que la colonne elle-même n'est pas vraiment cryptée, ce sont les données contenues dans cette colonne. Les colonnes elles-mêmes ne sont que des colonnes varbinaires (car c'est ce qui est nécessaire) et pourrait contenir des données totalement lisibles. C'est l'utilisation du ENCRYPTBY*
et DECRYPTBY*
Fonctions qui rendent vraiment les données cryptées.
Vous pouvez commencer simplement à interroger la vue Sys.Columns pour toutes les colonnes Varbinary:
select
object_name(a.object_id) [objectname]
,a.name [columnname]
,a.column_id
from
sys.columns a
join sys.types b on (a.system_type_id = b.system_type_id)
where
b.name = N'varbinary';
Sinon, vous devrez examiner votre code pour identifier où les fonctions de cryptage/de décryptage sont utilisées:
select
object_name(object_id) [objectname]
,definition
from
sys.sql_modules
where
definition like N'%ENCRYPT%'
OR definition like N'%DECRYPT%';
Exécutez la requête ci-dessous sur un DB spécifique
select
t.name as [Table],
c.name as [Column],
c.encryption_type_desc
from
sys.all_columns c inner join
sys.tables t on c.object_id = t.object_id
where
c.encryption_type is not null
order by
t.name,
c.name
Légèrement altéré de
Vous pouvez trouver les colonnes chiffrées avec des clés\certificats en recherchant toutes les colonnes varbinaires et la vérification d'une clé de cryptage avec la fonction Key_Name.
Cependant, ce processus est quelque peu coûteux et prend beaucoup de temps. Si vous avez besoin de trouver ces colonnes de manière régulière, je suggère de "marquer" les colonnes avec des propriétés étendues. Nous pouvons construire sur la solution d'Edward Dortland et "Tag" les colonnes trouvées avec des propriétés étendues telles que cryptées, chiffreriez et chiffrercert.
--create a table to hold all varbinary columns and tables
CREATE TABLE #TablesWithVarbinCols ( ID int IDENTITY,
SchemaName nvarchar(128),
TableName nvarchar(128),
ColumnName nvarchar(128)
);
--find and store all table and column names of user tables containing a
varbinary column
INSERT INTO #TablesWithVarbinCols (SchemaName,TableName,ColumnName)
SELECT s.[name] as SchemaName,
o.[name] as TableName,
c.[name] as ColumnName
FROM sys.objects o
INNER JOIN sys.schemas s
ON s.[schema_id] = o.[schema_id]
INNER JOIN sys.columns c
ON o.[object_id]=c.[object_id]
INNER JOIN sys.types t
ON c.system_type_id=t.system_type_id
WHERE o.[type]='U'
AND t.name=N'varbinary'
AND c.max_length > -1;
DECLARE @sch nvarchar(128)
DECLARE @col nvarchar(256)
DECLARE @tab nvarchar(256)
DECLARE @key nvarchar(256)
DECLARE @cert nvarchar(256)
DECLARE @c int = 1
DECLARE @MaxC int
DECLARE @SQL nvarchar(max)
SELECT @MaxC=MAX(ID)
FROM #TablesWithVarbinCols
--loop the previous result and create a simple select statement with a
key_name() is not null where clause.
--If you have a result, store the details
WHILE @c <= @MaxC
BEGIN
SET @key = NULL;
SELECT @sch=SchemaName,
@Tab=TableName,
@col=ColumnName
FROM #TablesWithVarbinCols
WHERE ID=@c
SET @SQL='SELECT DISTINCT @key= key_name('+@Col +') from '+ @tab +'
WHERE key_name('+@Col +') is not null;'
exec sp_executesql @SQL, N'@key nvarchar(256) out', @key out
SELECT @cert = c.name
from sys.symmetric_keys sk
join sys.key_encryptions ke
on
sk.symmetric_key_id= ke.key_id
join sys.certificates c
on
ke.thumbprint=c.thumbprint
where sk.name = @key
IF (@key IS NOT NULL)
BEGIN
SET @SQL=
'EXEC sp_addextendedproperty @name = N''encrypted'', @value = N''1'', '+
'@level0type = N''Schema'', @level0name = '''+@Sch+''', '+
'@level1type = N''Table'', @level1name = '''+@tab+''','+
'@level2type = N''Column'', @level2name = '''+@col+'''
'
EXEC sp_executesql @SQL
SET @SQL=
'EXEC sp_addextendedproperty @name = N''encryptkey'', @value = '''+@key+''', '+
'@level0type = N''Schema'', @level0name = '''+@Sch+''', '+
'@level1type = N''Table'', @level1name = '''+@tab+''','+
'@level2type = N''Column'', @level2name = '''+@col+'''
'
EXEC sp_executesql @SQL
SET @SQL=
'EXEC sp_addextendedproperty @name = N''encryptcert'', @value = '''+@cert+''', '+
'@level0type = N''Schema'', @level0name = '''+@Sch+''', '+
'@level1type = N''Table'', @level1name = '''+@tab+''','+
'@level2type = N''Column'', @level2name = '''+@col+'''
'
EXEC sp_executesql @SQL
END
DELETE
FROM #TablesWithVarbinCols
WHERE id=@c;
SET @c=@c+1
END
drop table #TablesWithVarbinCols
Ensuite, nous pouvons facilement trouver les colonnes cryptées en recherchant les propriétés étendues.
--Adjust WHERE clause depending on what tags you are looking for
SELECT
SCHEMA_NAME(tbl.schema_id) AS SchemaName,
tbl.name AS TableName,
clmns.name AS ColumnName,
p.name AS ExtendedPropertyName, --remove for programming
CAST(p.value AS sql_variant) AS ExtendedPropertyValue
FROM
sys.tables AS tbl
INNER JOIN sys.all_columns AS clmns ON clmns.object_id=tbl.object_id
INNER JOIN sys.extended_properties AS p ON p.major_id=tbl.object_id AND p.minor_id=clmns.column_id AND p.class=1
WHERE p.name in ('encrypted','encryptkey','encryptcert')