postgresql - pgp_sym_encrypt/pgp_sym_decrypt 错误处理

标签 postgresql encryption

我一直在使用 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/

相关文章:

sql-server-2008 - SQL Server 2008 + PCI 合规性?与 PCI 以及对称 key 有关!

c# - 是否可以在.NET 中生成 Multi-Prime RSA?

postgresql - Postgres JSONB 数据类型 - 如何从 Postgres 数据库的 JSON(JsonB 类型)字段中提取数据?

postgresql - Symfony2 - 如何限制用户可以存储的记录数?

postgresql - CREATE TABLE AS 不允许在 Postgresql 的非 volatile 函数中使用

javascript - 膨胀来自 websocket API 的响应

sql - 获取具有条件的关联记录数

postgresql - 如果参数为空,则无法查询 SQL 忽略部分 WHERE

ssl - Fiddler - 无法解密 SSL 流量 - 未指定的 CryptographicException

c - 可执行文件的加密