\df *crypt
dalam psql mengungkapkan tipe argumen dari pgcrypto encrypt
dan decrypt
fungsinya ( 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 encrypt
dan decrypt
fungsinya 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 encrypt
dengan 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_activity
dan sistem mencatat melalui log_statement
atau melalui pernyataan crypto yang gagal karena kesalahan. IMO seringkali lebih baik untuk melakukan crypto dalam aplikasi .
Saksikan sesi ini, dengan client_min_messages
diaktifkan 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_messages
cukup rendah. Sekarang di penyimpanan server, bersama dengan data yang dienkripsi. Gagal. Masalah yang sama tanpa log_statement
jika terjadi kesalahan yang menyebabkan pernyataan untuk dicatat, atau mungkin jika auto_explain
diaktifkan.
Paparan via pg_stat_activity
juga 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 TABLE
oleh penyerang yang tidak memiliki hak, hanya saja lebih sulit untuk menghitung waktu dengan benar. Serangan via pg_stat_activity
dapat dihindari dengan mencabut akses pg_stat_activity
dari 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.