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.
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 .. –
@ 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. –