TDE (Part II) : Performance et Volumétrie

  • Imprimer

 Cet article fait suite à TDE (Part I). Nous allons essayer de quantifier les impacts sur les performances de TDE, et aussi sur la volumétrie.

 

La documentation de TDE qui se trouve dans Advanced Security Administrator’s Guide, ne donne pas trop de détail sur les impacts de performance. Cependant, Oracle donne une piste dans un paragraphe introductif à TDE tablespace :

In addition, TDE tablespace encryption takes advantage of bulk encryption and caching to provide enhanced performance. While the actual performance impact on applications can vary, the performance overhead is roughly estimated to be in between 5% and 8%.

TDE tablespace encryption is a good alternative to TDE column encryption if your tables contain sensitive data in multiple columns, or if you want to protect the entire table and not just individual columns.

Nous pouvons en  déduire que TDE tablespace c’est une perte de performance d’environ 5% à 8%. Mais que c’est une bonne alternative à TDE colonne, surtout si il y a plusieurs colonnes à chiffrer, sous-entendu donc, que, par colonne, le chiffrage va être plus gourmand en performance.

Il n’y a pas de secret pour savoir combien on perd en performance il faut tester. Et, bien sûr, être au plus près de son application. Nous allons faire deux types de tests : un test qui met en évidence la baisse de performance dû aux restrictions sur les index. Puis un deuxième test qui met en évidence les différences de baisse de performance sur un select et un insert suivant les différents chiffrages sans être tributaire des restrictions sur les index.

 

Performance : effet de bords

Soit CRYT une table dans le tablespace chiffré USERS_CRYPT (voir TDE (Part I)):

CREATE TABLE crypt (
  id    NUMBER(10),  data  VARCHAR2(50),  data_crypt VARCHAR2(50)
) tablespace USERS_CRYPT;

COL_CRYPT, une table avec une colonne chiffrée sans sel:

CREATE TABLE col_crypt (
  id    NUMBER(10),  data  VARCHAR2(50),  data_crypt  VARCHAR2(50) ENCRYPT NO SALT
) tablespace USERS;

COL_SALT_CRYPT, une table avec une colonne chiffrée avec du sel:

CREATE TABLE col_salt_crypt (
  id    NUMBER(10),  data  VARCHAR2(50),  data_crypt  VARCHAR2(50) ENCRYPT  SALT
) tablespace USERS;

PAS_CRYPT, une table sans aucun chiffrage :

CREATE TABLE pas_crypt (
  id    NUMBER(10),  data  VARCHAR2(50),  data_crypt  VARCHAR2(50)
) tablespace USERS;

Nous remplissons les 4 tables avec la même procédure : TDE (Part II) : Annexe.

 Ensuite, nous créeons quand cela est possible un index sur la colonne data_crypt donc toutes les tables sauf col_salt_crypt:

create index col_crypt_data_idx on col_crypt(data_crypt) tablespace USERS;
create index crypt_data_idx on crypt(data_crypt) tablespace USERS_CRYPT;
create index pas_crypt_data_idx on pas_crypt(data_crypt) tablespace USERS;

Et maintenant le test, un select avec une clause sur la colonne data_crypt avec un like:

SQL>set timing on
SQL> select count(1) from col_crypt  where data_crypt like 'SECRET%';
  COUNT(1)
----------
     87822
Elapsed: 00:00:08.59

SQL> select count(1) from crypt  where data_crypt like 'SECRET%';
  COUNT(1)
----------
     94928
Elapsed: 00:00:00.02

SQL> select count(1) from col_salt_crypt  where data_crypt like 'SECRET%'
  COUNT(1)
----------
     95237
Elapsed: 00:00:10.61

SQL> select count(1) from pas_crypt  where data_crypt like 'SECRET%'
  COUNT(1)
----------
     94529
Elapsed: 00:00:00.02

Il n’y a aucun écart entre la table sans chiffrage et celle avec le chiffrage par tablespace.  En revanche avec les 2 tables qui ont du chiffrage par colonne c’est plus que 100% la perte de performance par rapport à aucun chiffrage. 450% pour le chiffrage sans sel et 530% pour chiffrage avec sel.

Avec une telle perte, il faudrait être fou pour faire du chiffrage par colonne !!!

Cela serait aller un peu vite en besogne, examinons le plan d’exécution de chaque requête.

Le plan exécution  pour la table chiffrée par colonne (avec ou sans sel) passe par un full scan de la table :

----------------------------------------------------------
Plan hash value: 1869455602
--------------------------------------------------------------------------------
| Id  | Operation                 | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                  |         1 |    19 |  2691    (1)  | 00:00:33 |
|   1 |  SORT AGGREGATE    |                   |         1 |    19 |                   |              |
|*  2 |   TABLE ACCESS FULL| COL_CRYPT  | 50000 |   927K|  2691    (1)| 00:00:33 |
--------------------------------------------------------------------------------

Alors que pour la table sans chiffrage ou bien la table dans le tablespace chiffré, l’index est pris en compte avec un balayage par index range:

----------------------------------------------------------
Plan hash value: 2044731059
------------------------------------------------------------------------------------
| Id  | Operation                | Name                 | Rows  | Bytes | Cost (%CPU)| Time    |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                           |          1 |         19 |   263   (1)| 00:00:04 |
|   1 |  SORT AGGREGATE   |                            |          1 |         19 |                |              |
|*  2 |   INDEX RANGE SCAN| CRYPT_DATA_IDX |  62500  |     1159K|   263   (1)| 00:00:04 |
------------------------------------------------------------------------------------

Voilà l’explication sur une telle différence de temps d’exécution. Ce n’est pas le chiffrage en lui-même qui cause entièrement cette perte de performance, mais la restriction sur les index. Pas d’ « index range scan » possible sur un index d’une colonne chiffrée, et carrément pas d’index possible sur une colonne chiffrée avec SALT donc forcément « table access full » dans les deux cas.

Ce test permet d’illustrer un effet de bord du chiffrage à prendre en compte avant de se lancer dans le chiffrage : les colonnes à chiffrer sont-elles des critères de recherche avec un opérateur comme like ? Doit-on les indexer, sachant que cela est impossible en mode colonne SALT ?...

 

Performance brute

A présent, faisons un test qui met en évidence la perte dû au chiffrage en lui-même. Nous allons faire de l’insert, du select, intensif mais avec le même plan d’exécution.

Pour cela nous créons un table toute simple, 2 colonnes, une de type NUMBER et l’autre de type VARCHAR2. Puis nous lançons le script TDE (Part II) : Annexe plsql qui la charge avec une boucle de 100.000 insertions, suivit d’une boucle de 100.000 select. Le script affiche en seconde le temps de l’insert, le temps du select et aussi tant que l’on y est la taille prise par la table. Puis nous recréons la table mais avec un autre chiffrage, ainsi de suite :

--- table non chiffrée
CREATE TABLE simple_table (  id    NUMBER(10),  data  VARCHAR2(50)) tablespace users;
@envoi_le_bourrier.sql
insert 667 select 19874 size 3Mo

@envoi_le_bourrier.sql
insert 567 select 19723 size 3Mo

--- table chiffrée par colonne NO SALT
CREATE TABLE simple_table (  id    NUMBER(10) encrypt no salt,  data  VARCHAR2(50) encrypt no salt) tablespace users;
@envoi_le_bourrier.sql
insert 1188 select 50174 size 9Mo

@envoi_le_bourrier.sql
insert 1181 select 50881 size 9Mo

--- table chiffrée par tablespace chiffré
CREATE TABLE simple_table (  id    NUMBER(10)  ,  data  VARCHAR2(50)) tablespace USERS_CRYPT;
@envoi_le_bourrier.sql
insert 791 select 20314 size 3Mo

@envoi_le_bourrier.sql
insert 814 select 20451 size 3Mo

--- table chiffrée par colonne SALT
CREATE TABLE simple_table (  id    NUMBER(10) encrypt ,  data  VARCHAR2(50) encrypt) tablespace users;
@envoi_le_bourrier.sql

 Stop au bout de 1h30!!!! Le script ne rend pas la main !

alors  en changeant le nombre d’itération de boucle de 100000 à 10000 soit

 l_loops  NUMBER := 10000;

Le script rend la main plus rapidement

@envoi_le_bourrier.sql
insert 287 select 356373   size 3Mo

 

100,000 lignes temps (s) perte performance % taille en Mo
insert select insert select 
Sans TDE 617 19799 N/A N/A 3
Colonne NO SALT 1185 50528 92% 155% 9
Colonne SALT * 1435 1781865 133% 8900% 15
Tablespace chiffré 803 20383 30% 3% 3

*: pour SALT le résultat obtenu pour 10.000 lignes a été multiplié par 10

Il n’y a pas photo, niveau performance le chiffrage de tablespace est bien plus performant que celui par colonne. Et pourtant il faut savoir que le tablespace est chiffré ici en AES256bit, alors que pour les colonnes, elles sont chiffrés en AES192bit (le par défaut).

Pour le chiffrage de tablespace, sur le select on obtient un pourcentage inférieur à celui annoncé par Oracle, une perte de 3%, mais pour la partie insertion c’est quand même une perte de 30%. Cela ne veut pas dire qu’une application va subir 3% globalement de baisse de performance sur la sélection et 30% sur l’insertion avec la mise en place du chiffrage de tablespace, car une application utilise, en général, plusieurs tables et le but est de ne chiffrer que les données sensibles. Ce qui signifie que seulement la sélection et l’insertion d’une partie des données est impacté par la baisse de performance.

Pour le chiffrage par colonne, les résultats obtenus ne donnent pas trop envie de mettre en place ce type de chiffrage. Cependant là aussi, il faut relativiser,  l’exemple couramment donné est le chiffrage du numéro de carte bleue. Si dans la base il faut chiffrer le numéro de carte bleu pour le protéger d’un vol physique de fichier, alors il y a de forte chance qu’un chiffrage uniquement sur cette colonne ne soit pas impactant ou très peu sur les performances. Cette colonne est une parfaite candidate car entre autre  il n’y a pas de raison de faire d’en faire un critère de recherche. Du coup, même un chiffrage avec un SALT pour augmenter sa sécurité, est conseillé.

Pour illustrer cela, nous allons maintenant supposer que la colonne id n’a aucune raison d’être protégée et seule la colonne data doit être protégée. Nous avons alors à choisir entre le chiffrage tablespace mais toute la table sera chiffré, ou bien le chiffrage par colonne, et seule la colonne data sera chiffrée.

 

CREATE TABLE simple_table (  id    NUMBER(10),  data  VARCHAR2(50) encrypt no salt) tablespace users;
@envoi_le_bourrier.sql
Insert : 1134 Select         : 24979 size : 6
Insert : 1100 Select         : 25611 size : 6

 

100,000 lignes temps (s) perte performance % taille en Mo
insert select insert select 
Sans TDE 617 19799 N/A N/A 3
toutes colonnes NO SALT 1185 50528 92% 155% 9
Colonne data NO SALT 1117 25295 81% 28% 6
Tablespace chiffré 803 20383 30% 3% 3

 

Nous n’avons pas beaucoup gagné sur l’insertion, en revanche sur la sélection nous avons grandement augmenté les performances même si les résultats sont encore inférieurs à ceux obtenus avec le tablespace chiffré.

Niveau performance donc il apparait assez clairement un avantage sur le chiffrage par tablespace par rapport au chiffrage colonne sans SALT et le avec SALT est complétement disqualifié. Mais si la perte de performance pour vous est acceptable, il y a aussi un autre effet à prendre en compte dans le chiffrage, c’est la volumétrie.

Volumétrie

. Lors des tests précédents nous avons relevé à chaque fois la taille de la table (voir tableaux) et nous avons vu des différences de volume entre les chiffrages. Et le chiffrage par tablespace arrive en tête pour le plus petit overhead de volume… il n’y en a pas. Le chiffrage par colonne est une fois de plus mauvaise élève et comme pour les performances le chiffrage avec SALT est le moins bon, ceux qui semble tout à fait logique : il y a du sel (chaine de caractère random) rajouté dans la donnée avant chiffrage. L’overhead n’est pas négligeable, x3 pour le NO SALT et x5 pour le SALT !!!


Conclusion

Chiffrage par tablespace vainqueur par KO.

Oui mais… nos tests portaient sur 100% de la base (une unique table), et si la base faisait 1To et que nous avions besoins de chiffrer seulement une colonne d’une table qui ne représente que 5% de la base et que cette colonne représente que 10% des colonnes de la table, cette perte de performance serait noyée…

En résumé, il faut savoir ce que l’on veut et surtout l’on doit chiffrer. Une fois les données à chiffrer identifiées, il faut se demander si elles sont candidates à être indexées et le volume qu’elles représentent : si une ou deux colonnes, non nécessairement indexables et de faible volume, alors peut être que le chiffrage par colonne sera une bonne solution. Il faut aussi connaitre la « sensibilité » de la colonne : le code de lancement de l’arme nucléaire doit être bien protégé par une bonne couche de sel, non ?

Si le chiffrage par colonne n’est pas performant, peut-être qu’il présente cependant d’autres avantages … rendez-vous prochainement dans un prochain article : TDE (part III) : key and rekey.

{jcomments on}