我一直在使用MySQL作为数据库,并计划转移到postgresql。我在整个应用程序中广泛使用了MySQL中的aes_encrypt和aes_decrypt函数。因此,只要加密/解密失败,MySQL就会自动返回'null'。
我不确定如何在postgresql中处理相同的内容。尝试使用pgp_sym_encrypt / pgp_sym_decrypt函数。如果加密密钥错误,则会抛出“错误的密钥/损坏的数据”错误。我尝试搜索一些可以捕获此错误并返回'null'的函数,因为我不需要修改我的代码。我一直在寻找,却找不到一个。
是否有人为个别查询使用了任何错误处理机制?我发现可以对程序进行错误处理。但是,我必须完全重写整个应用程序。
如果您可以分享一些细节,那将会有很大帮助。感谢。
答案 0 :(得分:4)
如果您希望避免修改代码并让函数在出错时返回NULL
,可以通过将它们包装在使用BEGIN ... EXCEPTION
块来捕获错误的PL / PgSQL函数中来完成此操作
要做到这一点,首先我得到错误的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关联的错误名称,发现它是泛型函数调用错误{{1 }}。不像我们希望的那样具体,但它会这样做。
现在需要一个包装函数。必须定义类似这样的内容,并为您希望支持的external_routine_invocation_exception
的每个重载签名使用一个函数。对于返回pgp_sym_decrypt
的{{1}}表单,例如:
(bytea,text)
我选择在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
请注意,两种形式都会显示函数失败时调用的参数。如果您使用了绑定参数(“预准备语句”),则不会显示这些参数,但如果您使用的是数据库内加密,则仍应将日志视为安全关键。
就个人而言,我认为在应用程序中进行加密更好,因此数据库永远无法访问密钥。