\df *crypt
trong psql tiết lộ các loại đối số của pgcrypto encrypt
và các decrypt
hàm ( cũng như các tài liệu 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
...
vì vậy cả hàm encrypt
và decrypt
hàm đều mong muốn khóa được bytea
. Theo thông báo lỗi, "bạn có thể cần thêm các kiểu phôi rõ ràng".
Tuy nhiên, nó hoạt động tốt ở đây trên trang 9.1, vì vậy tôi nghi ngờ có nhiều thứ hơn nó đã hiển thị. Có lẽ bạn có một chức năng khác cũng được đặt tên encrypt
với ba đối số?
Đây là cách nó hoạt động trên một bản sạch 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)
Awooga! Awooga! Rủi ro tiếp xúc chính, cần hết sức thận trọng của quản trị viên!
BTW, xin vui lòng suy nghĩ cẩn thận về việc liệu PGCrypto có thực sự là lựa chọn đúng đắn hay không. Các khóa trong truy vấn của bạn có thể được tiết lộ pg_stat_activity
và hệ thống đăng nhập thông qua log_statement
hoặc thông qua các câu lệnh về tiền điện tử không có lỗi. IMO thường xuyên tốt hơn để làm tiền điện tử trong ứng dụng .
Chứng kiến phiên này, với client_min_messages
tính năng được bật để bạn có thể thấy những gì sẽ xuất hiện trong nhật ký:
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)
Rất tiếc, khóa có thể bị lộ trong nhật ký nếu log_min_messages
đủ thấp. Giờ đây nó đã được lưu trữ trên máy chủ, cùng với dữ liệu được mã hóa. Thất bại. Vấn đề tương tự mà không log_statement
có lỗi xảy ra để làm cho câu lệnh được ghi lại, hoặc có thể nếu auto_explain
được bật.
Tiếp xúc qua pg_stat_activity
cũng có thể .. Mở hai phiên và:
- 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();
Rất tiếc! Lại có chìa khóa. Nó có thể được sao chép mà không LOCK TABLE
có kẻ tấn công không có đặc quyền, nó chỉ khó hơn để đúng lúc. Có pg_stat_activity
thể tránh được cuộc tấn công thông qua bằng cách thu hồi quyền truy cập pg_stat_activity
từ public
, nhưng nó chỉ cho thấy rằng có thể không tốt nhất để gửi khóa của bạn đến DB trừ khi bạn biết ứng dụng của mình là thứ duy nhất từng truy cập. Ngay cả sau đó, tôi không thích.
Nếu đó là mật khẩu, bạn có nên lưu trữ chúng không?
Hơn nữa, nếu bạn đang lưu trữ mật khẩu, đừng mã hóa hai chiều; nếu có thể có mật khẩu muối thì hãy băm chúng và lưu trữ kết quả . Bạn thường không cần phải có khả năng khôi phục mật khẩu Cleartext, chỉ xác nhận rằng hàm băm được lưu trữ khớp với mật khẩu mà người dùng gửi cho bạn để đăng nhập khi nó được băm với cùng một loại muối.
Nếu đó là auth, hãy để người khác làm điều đó cho bạn
Thậm chí tốt hơn, đừng lưu trữ mật khẩu, xác thực với LDAP, SASL, Active Directory, nhà cung cấp OAuth hoặc OpenID hoặc một số hệ thống bên ngoài khác đã được thiết kế và hoạt động.
Tài nguyên
và nhiều hơn nữa.