J'ai essayé le cryptage AES en utilisant la déclaration suivante:
SELECT encrypt('test', 'key', 'aes');
qui a fonctionné, mais je ne suis pas en mesure de décrypter la valeur. Je l'ai inséré dans un champ de type de données bytea mais je ne sais pas si c'était la bonne façon.
SELECT decrypt(pw, 'key', 'aes') FROM table WHERE ID = 1;
me donne l'erreur
ERREUR: la fonction de décryptage (bytea, unknown, unknown) n'existe pas
LIGNE 1: CHOISIR décrypter (pw, 'clé', 'aes') DE tabelle OERE ID = 7; ^
CONSEIL: Aucune fonction ne correspond au nom et aux types d'arguments donnés. Vous devrez peut-être ajouter des transtypages de types explicites.
Est-ce que cela signifie vraiment que encrypt () est une fonction existante, mais pas decrypt ()? Sinon, comment pourrais-je récupérer des valeurs cryptées aes?
\df *crypt
Dans psql révèle les types d'argument des fonctions pgcrypto encrypt
et decrypt
( comme le font les documents PgCrypto ):
List of functions
Schema | Name | Result data type | Argument data types | Type
--------+-----------------+------------------+--------------------------+--------
...
public | decrypt | bytea | bytea, bytea, text | normal
public | encrypt | bytea | bytea, bytea, text | normal
...
les fonctions encrypt
et decrypt
s'attendent donc à ce que la clé soit bytea
. Selon le message d'erreur, "vous devrez peut-être ajouter des transtypages de type explicites".
Cependant, cela fonctionne bien ici sur Pg 9.1, donc je pense qu'il y a plus que ce que vous avez montré. Peut-être avez-vous une autre fonction également nommée encrypt
avec trois arguments?
Voici comment cela fonctionne sur une Pg 9.1 propre:
regress=# create table demo(pw bytea);
CREATE TABLE
regress=# insert into demo(pw) values ( encrypt( 'data', 'key', 'aes') );
INSERT 0 1
regress=# select decrypt(pw, 'key', 'aes') FROM demo;
decrypt
------------
\x64617461
(1 row)
regress=# select convert_from(decrypt(pw, 'key', 'aes'), 'utf-8') FROM demo;
convert_from
--------------
data
(1 row)
BTW, réfléchissez bien si PgCrypto est vraiment le bon choix. Les clés de vos requêtes peuvent être révélées dans pg_stat_activity
Et les journaux système via log_statement
Ou via des instructions de chiffrement qui échouent avec une erreur. OMI, il est souvent préférable de faire de la cryptographie dans l'application .
Soyez témoin de cette session, avec client_min_messages
Activé afin que vous puissiez voir ce qui apparaîtrait dans les journaux:
regress# SET client_min_messages = 'DEBUG'; SET log_statement = 'all';
regress=# select decrypt(pw, 'key', 'aes') from demo;
LOG: statement: select decrypt(pw, 'key', 'aes') from demo;
LOG: duration: 0.710 ms
decrypt
------------
\x64617461
(1 row)
Oups, clé éventuellement exposée dans les journaux si log_min_messages
Est suffisamment bas. Il est maintenant sur le stockage du serveur, avec les données chiffrées. Échouer. Même problème sans log_statement
Si une erreur se produit pour provoquer la consignation de l'instruction, ou éventuellement si auto_explain
Est activé.
Une exposition via pg_stat_activity
Est également possible. Ouvrez deux sessions et:
BEGIN;
LOCK TABLE demo;
select decrypt(pw, 'key', 'aes') from demo;
select * from pg_stat_activity where current_query ILIKE '%decrypt%' AND procpid <> pg_backend_pid();
Oups! Voilà encore la clé. Il peut être reproduit sans le LOCK TABLE
Par un attaquant non privilégié, il est juste plus difficile de bien le chronométrer. L'attaque via pg_stat_activity
Peut être évitée en révoquant l'accès à pg_stat_activity
De public
, mais cela montre simplement qu'il n'est peut-être pas préférable d'envoyer votre clé à la base de données sauf si vous savez que votre application est la seule chose à y accéder. Même alors, je n'aime pas.
De plus, si vous stockez des mots de passe, ne les cryptez pas dans les deux sens; si possible sel les mots de passe, puis hachez-les et stockez le résultat . Vous n'avez généralement pas besoin de pouvoir récupérer le texte en clair du mot de passe, confirmez seulement que le hachage stocké correspond au mot de passe que l'utilisateur vous envoie pour vous connecter lorsqu'il est haché avec le même sel.
Encore mieux, ne stockez pas du tout le mot de passe, authentifiez-vous contre LDAP, SASL, Active Directory, un fournisseur OAuth ou OpenID, ou tout autre système externe qui est déjà conçu et fonctionne.
et beaucoup plus.