如何在 PostgreSQL 中使用 aes-encryption?

32b*_*oat 16 postgresql encryption functions postgresql-9.1

我使用以下语句尝试了 aes-encryption:

SELECT encrypt('test', 'key', 'aes');
Run Code Online (Sandbox Code Playgroud)

这有效,但我无法解密该值。我将它插入到数据类型bytea的字段中,但我不确定这是否正确。

SELECT decrypt(pw, 'key', 'aes') FROM table WHERE ID = 1;
Run Code Online (Sandbox Code Playgroud)

给我错误

错误:函数解密(bytea,未知,未知)不存在第
1 行:选择解密(密码,'key','aes')FROM tabelle WHERE ID = 7; ^
提示:没有函数匹配给定的名称和参数类型。您可能需要添加显式类型转换。

这是否真的意味着 encrypt() 是一个现有的函数,但不是decrypt()?我还能如何检索 aes 加密的值?

Cra*_*ger 20

\df *crypt在 psql 中显示了 pgcryptoencryptdecrypt函数的参数类型(与 PgCrypto 文档一样):

                                List of functions
 Schema |      Name       | Result data type |   Argument data types    |  Type  
--------+-----------------+------------------+--------------------------+--------
 ...
 public | decrypt         | bytea            | bytea, bytea, text       | normal
 public | encrypt         | bytea            | bytea, bytea, text       | normal
 ...
Run Code Online (Sandbox Code Playgroud)

所以 theencryptdecrypt函数都期望关键是bytea. 根据错误消息,“您可能需要添加显式类型转换”。

然而,它在 Pg 9.1 上运行良好,所以我怀疑它比你展示的更多。也许您还有另一个encrypt以三个参数命名的函数?

以下是它在干净的 Pg 9.1 上的工作方式:

regress=# create table demo(pw bytea);
CREATE TABLE
regress=# insert into demo(pw) values ( encrypt( 'data', 'key', 'aes') );
INSERT 0 1
regress=# select decrypt(pw, 'key', 'aes') FROM demo;
  decrypt   
------------
 \x64617461
(1 row)

regress=# select convert_from(decrypt(pw, 'key', 'aes'), 'utf-8') FROM demo;
 convert_from 
--------------
 data
(1 row)
Run Code Online (Sandbox Code Playgroud)

哇!哇!关键暴露风险,需要极其谨慎的管理员!

顺便说一句,请仔细考虑 PgCrypto 是否真的是正确的选择。查询中的密钥可以pg_stat_activity通过log_statement或通过因错误而失败的加密语句显示出来,并且系统会记录日志。IMO 通常最好在应用程序中进行加密

见证此会话,client_min_messages启用后您可以查看日志中显示的内容:

regress# SET client_min_messages = 'DEBUG'; SET log_statement = 'all'; 
regress=# select decrypt(pw, 'key', 'aes') from demo;
LOG:  statement: select decrypt(pw, 'key', 'aes') from demo;
LOG:  duration: 0.710 ms
  decrypt   
------------
 \x64617461
(1 row)
Run Code Online (Sandbox Code Playgroud)

哎呀,如果log_min_messages足够低,密钥可能会暴露在日志中。它现在与加密数据一起位于服务器的存储中。失败。同样的问题,log_statement如果发生错误导致语句被记录,或者可能是否auto_explain启用。

pg_stat_activity也可以通过曝光.. 打开两个会话,并且:

  • S1: BEGIN;
  • S1: LOCK TABLE demo;
  • S2: select decrypt(pw, 'key', 'aes') from demo;
  • S1: select * from pg_stat_activity where current_query ILIKE '%decrypt%' AND procpid <> pg_backend_pid();

哎呀!关键又来了。它可以在没有LOCK TABLE特权的攻击者的情况下进行复制,只是很难正确计时。pg_stat_activity通过撤销对pg_stat_activityfrom 的访问可以避免攻击 via public,但这只是表明将您的密钥发送到数据库可能不是最好的,除非您知道您的应用程序是唯一访问它的东西。即使那样,我也不喜欢。

如果是密码,您是否应该存储它们?

此外,如果您要存储密码,请不要对它们进行双向加密;如果有可能的盐密码,则将它们散列并存储结果。您通常不需要能够恢复密码明文,只需确认存储的哈希与用户发送给您登录的密码匹配,当它使用相同的盐进行哈希处理时。

如果是 auth,让别人为你做

更好的是,根本不要存储密码,不要针对 LDAP、SASL、Active Directory、OAuth 或 OpenID 提供程序或其他一些已经设计和运行的外部系统进行身份验证。

资源

还有更多。

  • 大声笑,“Awooga!Awooga!”+1 (3认同)