\df *crypt
w psql ujawnia typy argumentów pgcrypto encrypt
i decrypt
funkcji ( podobnie jak dokumenty 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
...
więc obie funkcje encrypt
i decrypt
oczekują, że klucz będzie bytea
. Zgodnie z komunikatem o błędzie „może być konieczne dodanie rzutowania typu jawnego”.
Jednak działa tutaj dobrze na stronie 9.1, więc podejrzewam, że jest w tym coś więcej niż pokazałeś. Być może masz inną funkcję o nazwie również encrypt
z trzema argumentami?
Oto jak działa na czystym Pg 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! Ryzyko narażenia na klucz, wymagana jest szczególna ostrożność administratora!
BTW, proszę dokładnie przemyśleć, czy PgCrypto jest naprawdę właściwym wyborem. Klucze w twoich zapytaniach mogą zostać ujawnione, pg_stat_activity
a system loguje się za pomocą log_statement
lub za pomocą instrukcji kryptograficznych, które kończą się błędem. IMO często lepiej jest zrobić kryptografię w aplikacji .
Obserwuj tę sesję z client_min_messages
włączoną funkcją, aby zobaczyć, co pojawi się w dziennikach:
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)
Ups, klucz może być ujawniony w logach, jeśli log_min_messages
jest wystarczająco niski. Jest teraz w pamięci serwera wraz z zaszyfrowanymi danymi. Zawieść. Ten sam problem bez log_statement
wystąpienia błędu powodującego zalogowanie się instrukcji lub ewentualnie auto_explain
włączenia.
pg_stat_activity
Możliwa jest także ekspozycja przez . Otwórz dwie sesje i:
- 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();
Ups! Znowu idzie klucz. Może zostać odtworzony bez LOCK TABLE
nieuprzywilejowanego atakującego, po prostu trudniej go odpowiednio zinterpretować. Ataku poprzez pg_stat_activity
można uniknąć, cofając dostęp dopg_stat_activity
z public
, ale to tylko dowodzi, że może nie być najlepiej wysłać swój klucz do DB, chyba że wiesz aplikacja jest jedyną rzeczą kiedykolwiek dostępu do niego. Nawet wtedy nie lubię.
Jeśli to hasła, czy w ogóle je przechowujesz?
Ponadto, jeśli przechowujesz hasła, nie szyfruj ich dwukierunkowo; jeśli w ogóle możliwe hasła soli, następnie je mieszaj i zapisz wynik . Zwykle nie musisz mieć możliwości odzyskania hasła w postaci tekstu jawnego, tylko potwierdź, że przechowywany skrót jest zgodny z hasłem, które użytkownik wysyła do zalogowania, gdy jest hashowane tą samą solą.
Jeśli to auth, niech ktoś zrobi to za ciebie
Co więcej, w ogóle nie przechowuj hasła, uwierzytelnij się przy użyciu LDAP, SASL, Active Directory, dostawcy OAuth lub OpenID lub innego systemu zewnętrznego, który został już zaprojektowany i działa.
Zasoby
i wiele więcej.
CREATE
bazę danych odtemplate0
; np.CREATE DATABASE testdb TEMPLATE template0
wtedyCREATE EXTENSION pgcrypto;
i przetestuj. Sprawdź, czy w szablonie 1 jest coś podejrzanego.