Làm cách nào để sử dụng mã hóa aes trong PostgreSQL?


15

Tôi đã thử mã hóa aes bằng cách sử dụng câu lệnh sau:

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

đã làm việc, nhưng tôi không thể giải mã giá trị. Tôi đã chèn nó vào một trường của datatype bytea nhưng tôi không chắc liệu đó có phải là cách đúng đắn hay không.

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

cho tôi lỗi

LRI: giải mã chức năng (bytea, chưa biết, chưa biết) không tồn tại
LINE 1: Giải mã CHỌN (pw, 'key', 'aes') TỪ tabelle WHERE ID = 7; ^
GỢI Ý: Không có chức năng nào khớp với các loại đối số và tên đã cho. Bạn có thể cần thêm phôi loại rõ ràng.

Điều đó thực sự có nghĩa là mã hóa () là một hàm hiện có, nhưng không giải mã ()? Làm thế nào khác tôi có thể truy xuất các giá trị được mã hóa aes?

Câu trả lời:


16

\df *crypttrong psql tiết lộ các loại đối số của pgcrypto encryptvà các decrypthà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 encryptdecrypthà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 encryptvớ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_activityvà hệ thống đăng nhập thông qua log_statementhoặ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_messagestí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_statementcó 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_activitycũ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 TABLEcó kẻ tấn công không có đặc quyền, nó chỉ khó hơn để đúng lúc. Có pg_stat_activitythể 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_activitytừ 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.


Nó không nhiều hơn tôi đã hiển thị và tôi đã không xác định các chức năng mới, đó là một postgresql mới được cài đặt. Điều khá khó chịu là mẫu của bạn và câu lệnh chọn đầu tiên tôi đã đăng cũng không hoạt động trong khi đó, trả lại lỗi tương tự như đã đăng ở trên. Đâu đó có gì đó không ổn ... cảm ơn vì câu trả lời của bạn.
32 bitfloat

Hãy thử trên một CREATEcơ sở dữ liệu mới từ template0; ví dụ CREATE DATABASE testdb TEMPLATE template0sau đó CREATE EXTENSION pgcrypto;và kiểm tra. Xem nếu có một cái gì đó tinh ranh trong template1.
Craig Ringer

Chỉ cần một lưu ý liên quan đến giải mã hai chiều trong db. Tôi không nghĩ rằng nó luôn luôn sai hướng, nhưng nó làm tăng thêm sự phức tạp và bất cứ nơi nào bạn đối phó với điều này, bạn thực sự phải đối phó với việc quản lý khóa có thể phức tạp hơn trong db.
Chris Travers

Ngoài ra 100% thứ hai quan niệm rằng bạn KHÔNG BAO GIỜ phải giải mã mật khẩu và việc móc vào một hệ thống được duy trì bởi nhiều người hơn thường là một chiến thắng bảo mật đáng kể.
Chris Travers

3
lol, +1 cho "Awooga! Awooga!"
Jeromy Pháp
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.