Postgresql

如何在 PostgreSQL 中使用 aes 加密?

  • October 13, 2021

我使用以下語句嘗試了 aes-encryption:

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

這有效,但我無法解密該值。我將它插入到數據類型bytea的欄位中,但我不確定這是否是正確的方法。

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

給我錯誤

錯誤:函式解密(bytea,未知,未知)不存在

第 1 行:從表 WHERE ID = 7 中選擇解密(pw,‘key’,‘aes’);^

提示:沒有函式匹配給定的名稱和參數類型。您可能需要添加顯式類型轉換。

這是否真的意味著 encrypt() 是一個現有函式,而不是 decrypt()?我還能如何檢索 aes 加密的值?

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

所以encryptdecrypt函式都期望 key 是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系統日誌中。IMO 通常最好在應用程序中進行加密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也可以通過以下方式曝光。打開兩個會話,然後:

  • 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特權的攻擊者的情況下被複製,只是更難正確計時。通過撤銷對frompg_stat_activity的訪問可以避免攻擊 via ,但這只是表明,除非您知道您的應用程序是唯一可以訪問它的東西,否則最好將您的密鑰發送到數據庫。即使那樣,我也不喜歡。pg_stat_activity``public

如果是密碼,您應該儲存它們嗎?

此外,如果您要儲存密碼,請不要對它們進行雙向加密;如果有所有可能的鹽密碼,則對它們進行雜湊處理並儲存結果。您通常不需要能夠恢復密碼明文,只需確認儲存的雜湊與使用者發送給您登錄的密碼匹配,當它使用相同的鹽進行雜湊處理時。

如果是 auth,讓別人為你做

更好的是,根本不儲存密碼,針對 LDAP、SASL、Active Directory、OAuth 或 OpenID 提供程序或其他一些已經設計和工作的外部系統進行身份驗證。

資源

還有更多。

引用自:https://dba.stackexchange.com/questions/24370