Bagaimana cara menggunakan aes-enkripsi di PostgreSQL?

15

Saya mencoba enkripsi aes dengan menggunakan pernyataan berikut:

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

yang berhasil, tetapi saya tidak dapat mendekripsi nilainya. Saya memasukkannya dalam bidang byteat datatype tapi saya tidak yakin apakah itu cara yang benar.

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

memberi saya kesalahan

GALAT: fungsi mendekripsi (bytea, tidak diketahui, tidak diketahui) tidak ada
LINE 1: PILIH dekripsi (pw, 'key', 'aes') DARI tabelle WHERE ID = 7; ^
PETUNJUK: Tidak ada fungsi yang cocok dengan nama dan tipe argumen yang diberikan. Anda mungkin perlu menambahkan gips tipe eksplisit.

Apakah itu benar-benar berarti bahwa mengenkripsi () adalah fungsi yang sudah ada, tetapi tidak mendekripsi ()? Bagaimana lagi saya bisa mengambil kembali nilai-nilai yang dienkripsi aes?

32 bit mengapung
sumber

Jawaban:

16

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

Craig Ringer
sumber
Ini tidak lebih dari yang saya tunjukkan, dan saya tidak mendefinisikan fungsi baru, ini adalah postgresql yang baru diinstal. Sangat menjengkelkan bahwa sampel Anda dan pernyataan pilih-pertama yang saya posting juga tidak berfungsi, mengembalikan kesalahan yang sama seperti yang diposting di atas. Di suatu tempat ada yang tidak beres ... terima kasih atas jawaban Anda.
32bit naik
Coba pada CREATEdatabase d baru dari template0; misalnyaCREATE DATABASE testdb TEMPLATE template0 kemudian CREATE EXTENSION pgcrypto;dan uji. Lihat apakah ada sesuatu yang cerdik di template1.
Craig Ringer
Hanya sebuah catatan tentang dekripsi dua arah di db. Saya tidak berpikir itu selalu salah arah tetapi, itu menambah kompleksitas dan di mana pun Anda berurusan dengan ini Anda benar-benar harus berurusan dengan manajemen kunci yang bisa lebih rumit di db.
Chris Travers
Juga 100% detik gagasan bahwa Anda TIDAK PERNAH harus mendekripsi kata sandi dan bahwa menghubungkan ke sistem yang dikelola oleh lebih banyak orang biasanya merupakan solusi keamanan yang signifikan.
Chris Travers
3
lol, +1 untuk "Awooga! Awooga!"
Jeromy French