2012-11-28 13 views
7

Avevo usato MySQL come database e avevo programmato di passare a postgresql. Avevo già utilizzato le funzioni aes_encrypt e aes_decrypt in MySQL per tutta la mia applicazione. Quindi, ogni volta che la crittografia/decrytion fallisce, MySQL restituisce automaticamente "null".pgp_sym_encrypt/pgp_sym_decrypt gestione degli errori

Non so come gestire lo stesso in postgresql. Ho provato a utilizzare le funzioni pgp_sym_encrypt/pgp_sym_decrypt. Se la chiave di crittografia è sbagliata, genera l'errore "Chiave errata/dati corrotti". Ho provato a cercare alcune funzioni in grado di catturare questo errore e restituire 'null' come in MySQL in modo che non debba modificare il mio codice. Stavo cercando ma non riuscivo a trovarne uno.

Qualcuno ha utilizzato un meccanismo di gestione degli errori per singole query? Avevo scoperto che la gestione degli errori può essere eseguita per le procedure. Ma ho dovuto riscrivere completamente l'intera applicazione per quello.

Se potessi condividere alcuni dettagli, sarebbe di grande aiuto. Grazie.

risposta

4

Se si desidera evitare di modificare il codice e fare in modo che le funzioni restituiscano NULL in caso di errore, è possibile eseguire questa operazione avvolgendoli in una funzione PL/PgSQL che utilizza un blocco BEGIN ... EXCEPTION per intercettare l'errore.

Per fare questo, prima ho l'SQLSTATE per l'errore:

regress=# \set VERBOSITY verbose 
regress=# SELECT pgp_sym_decrypt('fred','key'); 
ERROR: 39000: Wrong key or corrupt data 
LOCATION: decrypt_internal, pgp-pgsql.c:607 

ho potuto utilizzare questo direttamente nel gestore di errori, ma io preferisco usare un nome simbolico, in modo da cercare il nome di errore associato a 39000 in Appendix A - Error codes, rilevando che si tratta della funzione generica chiamata errore external_routine_invocation_exception. Non così specifico come avremmo voluto, ma lo farà.

Ora è richiesta una funzione wrapper. Qualcosa di simile deve essere definito, con una funzione per ogni firma sovraccaricata di pgp_sym_decrypt che si desidera supportare. Per la forma (bytea,text) che restituisce text, ad esempio:

CREATE OR REPLACE FUNCTION pgp_sym_decrypt_null_on_err(data bytea, psw text) RETURNS text AS $$ 
BEGIN 
    RETURN pgp_sym_decrypt(data, psw); 
EXCEPTION 
    WHEN external_routine_invocation_exception THEN 
    RAISE DEBUG USING 
     MESSAGE = format('Decryption failed: SQLSTATE %s, Msg: %s', 
         SQLSTATE,SQLERRM), 
     HINT = 'pgp_sym_encrypt(...) failed; check your key', 
     ERRCODE = 'external_routine_invocation_exception'; 
    RETURN NULL; 
END; 
$$ LANGUAGE plpgsql; 

Ho scelto di preseve l'errore originale in un messaggio DEBUG livello. Ecco un confronto tra l'originale e il wrapper, con piena verbosità del messaggio e output di livello di debug.

Abilita output di debug per mostrare RAISE. Si noti che mostra anche il * testo della query originale della chiamata pgp_decrypt_sym, inclusi i parametri.

regress=# SET client_min_messages = DEBUG; 

nuova avvolto funzione segnala ancora l'errore se la registrazione dettagliata è abilitata, ma restituisce NULL:

regress=# SELECT pgp_sym_decrypt_null_on_err('redsdfsfdsfd','bobsdf'); 
LOG: 00000: statement: SELECT pgp_sym_decrypt_null_on_err('redsdfsfdsfd','bobsdf'); 
LOCATION: exec_simple_query, postgres.c:860 
DEBUG: 39000: Decryption failed: SQLSTATE 39000, Msg: Wrong key or corrupt data 
HINT: pgp_sym_encrypt(...) failed; check your key 
LOCATION: exec_stmt_raise, pl_exec.c:2806 
pgp_sym_decrypt_null_on_err 
----------------------------- 

(1 row) 

rispetto all'originale, che non riesce:

regress=# SELECT pgp_sym_decrypt('redsdfsfdsfd','bobsdf'); 
LOG: 00000: statement: SELECT pgp_sym_decrypt('redsdfsfdsfd','bobsdf'); 
LOCATION: exec_simple_query, postgres.c:860 
ERROR: 39000: Wrong key or corrupt data 
LOCATION: decrypt_internal, pgp-pgsql.c:607 

noti che sia le forme mostrano i parametri con cui la funzione è stata chiamata quando ha fallito. I parametri non verranno visualizzati se sono stati utilizzati i parametri di bind ("istruzioni preparate"), ma è comunque necessario considerare i registri come critici per la sicurezza se si utilizza la crittografia nel database.

Personalmente, penso che sia meglio fare crypto nell'app, quindi il DB non ha mai accesso alle chiavi.

+0

grazie per la risposta.Ho deciso di implementare una funzione di questo tipo come ultima risorsa. Davvero molto utile. Sto cercando di ottenere il massimo dalle funzioni pgsql in-build. Fammi vedere quanto meglio ti aiuta. Inoltre, grazie per il tuo suggerimento di fare tutto il crypto nell'app .. sì, ecco come avevo già programmato di cambiare alcune funzionalità critiche nell'app. in seguito cambierò tutto .. –

+0

@ user1365983 Bene - Non penso che sia una buona idea, quindi sono contento che tu non abbia intenzione di farlo. Si prega di accettare la risposta se fosse utile, utilizzando il segno di spunta sotto il punteggio di risposta in alto a sinistra. –