我一直在使用 MySQL 作为数据库,并计划迁移到 postgresql。我在整个应用程序中广泛使用了 MySQL 中的 aes_encrypt 和 aes_decrypt 函数。因此,每当加密/解密失败时,MySQL 会自动返回 'null'。
我不确定如何在 postgresql 中处理相同的问题。尝试使用 pgp_sym_encrypt/pgp_sym_decrypt 函数。如果加密 key 错误,它会抛出错误“Wrong key/corrupt data”。我尝试搜索一些可以捕获此错误并像在 MySQL 中那样返回“null”的函数,这样我就不需要修改我的代码。我一直在寻找,但找不到。
有没有人对个别查询使用过任何错误处理机制?我发现可以对过程进行错误处理。但是,我不得不为此完全重写整个应用程序。
如果你能分享一些细节,那将有很大帮助。谢谢。
最佳答案
如果您希望避免修改您的代码并让函数在出错时返回 NULL
,您可以通过将它们包装在一个使用 BEGIN ... EXCEPTION
block 以捕获错误。
为此,我首先获取错误的 SQLSTATE:
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
我可以直接在错误处理程序中使用它,但我更喜欢使用符号名称,所以我在 Appendix A - Error codes 中查找与 39000 关联的错误名称,发现是通用函数调用错误external_routine_invocation_exception
。没有我们希望的那么具体,但它会做到。
现在需要一个包装函数。必须定义类似这样的东西,为您希望支持的 pgp_sym_decrypt
的每个重载签名定义一个函数。对于返回text
的(bytea,text)
形式,例如:
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;
我已选择在 DEBUG
级别消息中保留原始错误。这是原始和包装器的比较,具有完整的消息详细程度和调试级别输出。
启用调试输出以显示 RAISE
。请注意,它还显示了 pgp_decrypt_sym
调用的*原始查询文本,包括参数。
regress=# SET client_min_messages = DEBUG;
如果启用了详细日志记录,新包装函数仍会报告错误,但会返回 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)
与失败的原始版本相比:
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
请注意,两种形式都显示函数在失败时调用的参数。如果您使用了绑定(bind)参数(“准备好的语句”),则不会显示这些参数,但如果您使用数据库内加密,您仍应将日志视为安全关键。
就我个人而言,我认为最好在应用程序中进行加密,这样数据库就永远无法访问 key 。
关于postgresql - pgp_sym_encrypt/pgp_sym_decrypt 错误处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13598704/