Jeśli chcesz uniknąć modyfikacji kodu i funkcje zwracają NULL
w przypadku błędu, możesz to zrobić, owijając je w funkcję PL/PgSQL, która używa bloku BEGIN ... EXCEPTION
, aby uwięzić błąd.
Aby to zrobić, należy najpierw uzyskać SQLSTATE błędu:
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
mogę użyć tego bezpośrednio w module obsługi błędów, ale wolę używać nazwy symboliczne, więc patrzę nazwę błędzie związane z 39000 w Appendix A - Error codes, ustalając, że jest to ogólny błąd wywołania funkcji external_routine_invocation_exception
. Nie tak szczegółowe, jak byśmy sobie życzyli, ale zrobi to.
Teraz potrzebna jest funkcja opakowania. Coś takiego musi być zdefiniowane, z jedną funkcją dla każdego przeciążonego podpisu pgp_sym_decrypt
, którą chcesz wspierać. Dla postaci (bytea,text)
zwracającej text
, na przykład:
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;
wybrałem preseve oryginalny błąd w wiadomości DEBUG
poziomu. Oto porównanie oryginału i opakowania, z pełną szczegółowością komunikatu i wyjściem z poziomu debugowania.
Włącz wyjście debugowania, aby wyświetlić RAISE
. Zauważ, że pokazuje również * oryginalny tekst zapytania połączenia pgp_decrypt_sym
, w tym parametry.
regress=# SET client_min_messages = DEBUG;
New owinięty funkcja nadal zgłasza błąd, jeśli szczegółowe rejestrowanie jest włączone, ale zwraca 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)
porównaniu do oryginału, który kończy się niepowodzeniem:
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
Zauważ, że zarówno formularze wyświetlają parametry, z którymi wywołano funkcję, gdy nie powiodło się. Parametry nie będą wyświetlane, jeśli zostały użyte parametry powiązania ("przygotowane instrukcje"), ale nadal należy uważać dzienniki za krytyczne z punktu widzenia bezpieczeństwa, jeśli używasz szyfrowania w bazie danych.
Osobiście uważam, że lepiej jest zrobić crypto w aplikacji, aby baza danych nigdy nie miała dostępu do kluczy.
dziękuję za odpowiedź.Postanowiłem pójść na realizację takiej funkcji w ostateczności. Rzeczywiście bardzo przydatne. Próbuję uzyskać maksimum z wbudowanych funkcji pgsql. Pozwól mi zobaczyć, jak najlepiej pomaga. Dziękuję również za sugestię, aby wykonać całą kryptografię w aplikacji. Tak, tak już planowałem zmienić kilka ważnych funkcji w aplikacji. Później zmienię wszystko. –
@ user1365983 Dobrze - Nie sądzę, że to bardzo dobry pomysł, więc cieszę się, że nie planujesz tego zrobić. Zaakceptuj odpowiedź, jeśli była pomocna, za pomocą zaznaczenia pod wynikiem odpowiedzi w lewym górnym rogu. –