\df *cryptin psql rivela i tipi di argomenti di pgcrypto encrypte decryptfunzioni (così come i documenti 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
...
quindi entrambe le funzioni encrypte si decryptaspettano che la chiave sia bytea. Come da messaggio di errore, "potrebbe essere necessario aggiungere cast di tipo esplicito".
Tuttavia, funziona bene qui a Pg 9.1, quindi sospetto che ci sia molto di più di quanto tu abbia mostrato. Forse hai un'altra funzione chiamata anche encryptcon tre argomenti?
Ecco come funziona su una Pg 9.1 pulita:
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)
Awooga! Awooga! Rischio chiave di esposizione, è richiesta estrema cautela da parte dell'amministratore!
A proposito, ti preghiamo di pensare attentamente se PgCrypto è davvero la scelta giusta. Le chiavi delle query possono essere rivelate pg_stat_activitye il sistema accede tramite log_statemento tramite istruzioni crittografiche che non riescono con un errore. IMO è spesso meglio fare criptovalute nell'applicazione .
Prova questa sessione, con client_min_messagesabilitato in modo da poter vedere cosa apparirebbe nei registri:
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)
Whoops, chiave eventualmente esposta nei registri se log_min_messagesè abbastanza bassa. Ora è nella memoria del server, insieme ai dati crittografati. Fallire. Stesso problema senza log_statementche si verifichi un errore che causi il log dell'istruzione, o possibilmente se auto_explainabilitato.
pg_stat_activityÈ anche possibile l' esposizione tramite . Aprire due sessioni e:
- S1:
BEGIN;
- S1:
LOCK TABLE demo;
- S2:
select decrypt(pw, 'key', 'aes') from demo;
- S1:
select * from pg_stat_activity where current_query ILIKE '%decrypt%' AND procpid <> pg_backend_pid();
Ops! Ecco di nuovo la chiave. Può essere riprodotto senza il LOCK TABLEda un attaccante senza privilegi, è solo più difficile cronometrarlo nel modo giusto. L'attacco tramite pg_stat_activitypuò essere evitato revocando l'accesso a pg_stat_activityda public, ma ciò dimostra che potrebbe non essere meglio inviare la chiave al DB a meno che tu non sappia che la tua app è l'unica cosa ad accedervi. Anche allora, non mi piace.
Se si tratta di password, dovresti memorizzarle?
Inoltre, se stai memorizzando le password, non crittografarle in due modi; se possibile tutte le password salt, quindi cancellale e memorizza il risultato . Di solito non è necessario essere in grado di recuperare il testo in chiaro della password, confermare solo che l'hash memorizzato corrisponde alla password che l'utente ti invia per accedere quando è hash con lo stesso salt.
Se è auth, lascia che qualcun altro lo faccia per te
Ancora meglio, non archiviare affatto la password, eseguire l'autenticazione con LDAP, SASL, Active Directory, un provider OAuth o OpenID o qualche altro sistema esterno già progettato e funzionante.
risorse
e molto altro.