\df *cryptdalam psql mengungkapkan tipe argumen dari pgcrypto encryptdan decryptfungsinya ( seperti halnya dokumen 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
...
jadi keduanya encryptdan decryptfungsinya mengharapkan kuncinya bytea. Sesuai pesan kesalahan, "Anda mungkin perlu menambahkan gips tipe eksplisit".
Namun, ini berfungsi dengan baik di sini di Pg 9.1, jadi saya curiga ada yang lebih dari yang Anda tunjukkan. Mungkin Anda memiliki fungsi lain yang juga dinamai encryptdengan tiga argumen?
Begini cara kerjanya pada Pg 9.1 yang bersih:
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)
Awooga! Awooga! Risiko pajanan utama, diperlukan kehati-hatian admin ekstrim!
BTW, tolong pikirkan baik-baik apakah PgCrypto benar-benar pilihan yang tepat. Kunci dalam kueri Anda dapat diungkapkan pg_stat_activitydan sistem mencatat melalui log_statementatau melalui pernyataan crypto yang gagal karena kesalahan. IMO seringkali lebih baik untuk melakukan crypto dalam aplikasi .
Saksikan sesi ini, dengan client_min_messagesdiaktifkan sehingga Anda dapat melihat apa yang muncul di log:
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)
Aduh, kunci mungkin terbuka di log jika log_min_messagescukup rendah. Sekarang di penyimpanan server, bersama dengan data yang dienkripsi. Gagal. Masalah yang sama tanpa log_statementjika terjadi kesalahan yang menyebabkan pernyataan untuk dicatat, atau mungkin jika auto_explaindiaktifkan.
Paparan via pg_stat_activityjuga dimungkinkan .. Buka dua sesi, dan:
- 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();
Aduh! Kuncinya ada lagi. Ini dapat direproduksi tanpa LOCK TABLEoleh penyerang yang tidak memiliki hak, hanya saja lebih sulit untuk menghitung waktu dengan benar. Serangan via pg_stat_activitydapat dihindari dengan mencabut akses pg_stat_activitydari public, tetapi itu hanya menunjukkan bahwa mungkin bukan yang terbaik untuk mengirim kunci Anda ke DB kecuali Anda tahu aplikasi Anda adalah satu-satunya hal yang pernah mengaksesnya. Meski begitu, saya tidak suka.
Jika itu kata sandi, haruskah Anda menyimpannya sama sekali?
Selain itu, jika Anda menyimpan kata sandi, jangan enkripsi dua arah; jika mungkin password garam kemudian hash mereka dan simpan hasilnya . Anda biasanya tidak perlu dapat memulihkan kata sandi, hanya mengkonfirmasi bahwa hash yang disimpan cocok dengan kata sandi yang dikirim oleh pengguna untuk Anda masuk ketika hash dengan garam yang sama.
Jika itu auth, biarkan orang lain melakukannya untuk Anda
Lebih baik lagi, jangan menyimpan kata sandi sama sekali, otentikasi terhadap LDAP, SASL, Direktori Aktif, penyedia OAuth atau OpenID, atau sistem eksternal lain yang sudah dirancang dan berfungsi.
Sumber daya
dan banyak lagi.