web-dev-qa-db-ja.com

PostgreSQLでaes-encryptionを使用する方法

次のステートメントを使用してaes-encryptionを試しました:

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

うまくいきましたが、値を復号化できません。データ型byteaのフィールドに挿入しましたが、それが正しい方法かどうかはわかりません。

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

エラーが出ます

エラー:関数の復号化(bytea、不明、不明)は存在しません
行1:SELECT(pw、 'key'、 'aes')FROM tabelle WHERE ID = 7; ^
ヒント:指定された名前と引数の型に一致する関数はありません。明示的な型キャストを追加する必要がある場合があります。

それは本当に、encrypt()が既存の関数であり、decrypt()ではないということですか?他にどのようにaesで暗号化された値を取得できますか?

15
32bitfloat

psqlの_\df *crypt_は、pgcrypto encryptおよびdecrypt関数の引数の型を示します( 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
 ...
_

したがって、encrypt関数とdecrypt関数はどちらも、キーがbyteaであることを期待しています。エラーメッセージに従って、「明示的な型キャストを追加する必要がある場合があります」。

ただし、ここではPg 9.1で正常に機能するため、表示されている以上の機能があると思います。おそらく、3つの引数を持つ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_による露出も可能です。2つのセッションを開いて、

  • 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_を介した攻撃は、publicから_pg_stat_activity_へのアクセスを取り消すことで回避できますが、知らない限り、DBにキーを送信するのが最善ではない可能性があることを示しています。アプリは、これにアクセスする唯一のものです。それでも、私は好きではありません。

パスワードの場合は、保存する必要がありますか?

さらに、パスワードを保存する場合は、双方向の暗号化を行わないでください。可能な限りソルトパスワードをハッシュしてハッシュし、結果を保存します。通常、パスワードのクリアテキストを復元する必要はありません。保存されているハッシュが、同じソルトでハッシュされたときにユーザーがログインするために送信するパスワードと一致することを確認するだけです。

Authの場合は、他の人にやってもらいましょう

さらに良いのは、パスワードをまったく保存せず、LDAP、SASL、Active Directory、OAuthまたはOpenIDプロバイダー、またはすでに設計され機能している他の外部システムに対して認証を行うことです。

資源

そしてもっとたくさん。

16
Craig Ringer