我使用以下语句尝试aes加密:
SELECT encrypt('test', 'key', 'aes');这起作用了,但我无法解密这个值。我把它插入了一个数据类型字段,但是我不确定这是不是正确的方法。
SELECT decrypt(pw, 'key', 'aes') FROM table WHERE ID = 1;给了我错误
错误:函数解密(字节,未知,未知)不存在第1行:从ID =7的表中选择解密(pw,'key','aes');^提示:没有函数匹配给定的名称和参数类型。您可能需要添加显式类型转换。
这是否真的意味着encrypt()是一个现有的函数,而不是解密()?不然我怎么能收回aes加密的值呢?
发布于 2012-09-16 04:57:11
psql中的\df *crypt揭示了pgcrypto encrypt和decrypt函数(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
...因此,encrypt和decrypt函数都期望密钥是bytea。根据错误消息,“您可能需要添加显式类型强制转换”。
然而,它在这里很好的第9.1,所以我怀疑它有比你已经显示的更多。也许你还有另外一个函数,也叫encrypt,它有三个参数?
下面是它在一个干净的P9.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显示,也可以通过密码语句显示,如果出现错误,则会失败。通常情况下,在应用程序中做密码比较好。
在启用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暴露也是可能的。举行两次会议,并:
BEGIN;LOCK TABLE demo;select decrypt(pw, 'key', 'aes') from demo;select * from pg_stat_activity where current_query ILIKE '%decrypt%' AND procpid <> pg_backend_pid();哇哦!钥匙又来了。它可以在没有LOCK TABLE的情况下由无特权的攻击者复制,只是很难对其进行正确的时间安排。通过pg_stat_activity进行的攻击可以通过从public撤销对pg_stat_activity的访问来避免,但它只是表明,除非您知道应用程序是唯一访问它的东西,否则向DB发送密钥可能不是最好的方法。即使如此,我也不喜欢。
此外,如果您正在存储密码,则不要对其进行双向加密;如果有可能,则对其进行散列并存储结果。您通常不需要恢复密码明文,只需确认所存储的散列是否与用户发送给您的密码匹配,当使用相同的盐分进行散列时。
如果是
更好的是,根本不要存储密码,使用LDAP、SASL、Active Directory、OAuth或OpenID提供程序或其他已经设计和工作的外部系统进行身份验证。
还有更多。
https://dba.stackexchange.com/questions/24370
复制相似问题