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 中显示了 pgcryptoencrypt
和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
...
Run Code Online (Sandbox Code Playgroud)
所以 theencrypt
和decrypt
函数都期望关键是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
也可以通过曝光.. 打开两个会话,并且:
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
通过撤销对pg_stat_activity
from 的访问可以避免攻击 via public
,但这只是表明将您的密钥发送到数据库可能不是最好的,除非您知道您的应用程序是唯一访问它的东西。即使那样,我也不喜欢。
此外,如果您要存储密码,请不要对它们进行双向加密;如果有可能的盐密码,则将它们散列并存储结果。您通常不需要能够恢复密码明文,只需确认存储的哈希与用户发送给您登录的密码匹配,当它使用相同的盐进行哈希处理时。
更好的是,根本不要存储密码,不要针对 LDAP、SASL、Active Directory、OAuth 或 OpenID 提供程序或其他一些已经设计和运行的外部系统进行身份验证。
还有更多。