如何在PostgreSQL中使用AES加密?


15

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

SELECT encrypt('test', 'key', 'aes');

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

SELECT decrypt(pw, 'key', 'aes') FROM table WHERE ID = 1;

给我错误

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

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

Answers:


16

\df *crypt在psql中显示了pgcrypto encryptdecrypt函数的参数类型(与PgCrypto docs一样):

                                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
 ...

因此encryptdecrypt功能都希望键是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)

天啊!天啊!关键暴露风险,需要管理员特别注意!

顺便说一句,请仔细考虑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)

糟糕,如果密钥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_activitypublic,但这只是表明,除非您知道自己的应用程序是唯一访问它的方法,否则最好将密钥发送给数据库。即使那样,我也不喜欢。

如果是密码,应该完全存储吗?

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

如果是授权,请让其他人为您完成

甚至更好的是,根本不存储密码,无需通过LDAP,SASL,Active Directory,OAuth或OpenID提供程序或已经设计并运行的某些其他外部系统进行身份验证。

资源资源

还有更多。


它不超过我所显示的,并且我没有定义新功能,而是新安装的postgresql。令人不安的是,您的示例和我发布的第一个选择语句也无法同时工作,返回与上面发布的错误相同的错误。某个地方出了问题...无论如何都要感谢您的回答。
32bitfloat 2012年

试用来自的新CREATE数据库template0。例如CREATE DATABASE testdb TEMPLATE template0然后CREATE EXTENSION pgcrypto;测试。看看template1中是否有躲猫猫。
Craig Ringer 2012年

只是有关数据库中双向解密的注释。我不认为这总是错误的方向,但是,它增加了复杂性,在您处理此问题的任何地方,您实际上都必须处理密钥管理,这在数据库中可能会更加复杂。
克里斯·特拉弗斯

同样100%的观点是,您永远不必解密密码,并且挂在由更多人维护的系统上通常是一个重大的安全胜利。
克里斯·特拉弗斯

3
大声笑,+ 1表示“ Awooga!Awooga!”
Jeromy French
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.