Pilihan pendekatan otentikasi untuk aplikasi keuangan di PostgreSQL

15

Pertama beberapa latar belakang.

Proyek LedgerSMB adalah proyek perangkat lunak akuntansi keuangan open source yang berjalan di PostgreSQL. Kami menerapkan logika bisnis dalam jumlah yang sangat besar dalam fungsi yang ditentukan pengguna, yang bertindak sebagai alat pemetaan utama antara metode objek program dan perilaku database. Saat ini kami menggunakan pengguna basis data sebagai pengguna otentikasi, sebagian karena pilihan (ini memungkinkan logika keamanan terpusat, sehingga alat lain dapat ditulis dan menggunakan kembali izin yang diberikan kepada pengguna), dan sebagian oleh kebutuhan (setelah kami bercabang dari SQL-Ledger, ada tidak banyak opsi untuk memperbaiki keamanan ke basis kode itu).

Ini memberi kita akses ke sejumlah opsi masuk tunggal yang masuk akal yang dapat diakses PostgreSQL, dari LDAP ke Kerberos 5. Kita bahkan dapat menggunakan PAM yang terkait dengan kata sandi. Itu juga memungkinkan kita untuk menggunakan kembali izin ketika berintegrasi dengan aplikasi lain, atau mengizinkan antarmuka klien lain. Untuk aplikasi akuntansi keuangan, ini seperti kemenangan bersih.

Jelas ada biaya yang harus dikeluarkan. Untuk aplikasi web, kami sangat terbatas pada jenis auth http yang dapat didukung. DIGEST misalnya sepenuhnya keluar. BASIC berfungsi, dan kami dapat mengimplementasikan KRB5 dengan cukup mudah (saya berencana untuk mendukung dan bekerja di luar kotak ini untuk 1.4). Tindakan otentikasi yang sangat kuat tidak dapat dikelola dengan baik secara langsung ini meskipun kami mungkin dapat mengacaukannya jika perlu (misalnya BASIC + sertifikat sisi klien SSL dengan cn yang cocok dengan nama pengguna dan ca root tertentu).

Pada saat yang sama, kami mendapat banyak kecaman sebagian besar dari kerumunan pengembangan dan lebih sering dari dba yang mengatakan kepada saya bahwa aplikasi harus menjadi penghalang keamanan, bukan database. Pandangan saya masih bahwa perimeter keamanan yang lebih kecil umumnya lebih baik, bahwa penggunaan kembali logika bisnis dan logika keamanan berjalan bersama, dan bahwa menurut saya berbahaya untuk menggunakan kembali logika bisnis tanpa menggunakan kembali logika keamanan pada tingkat yang sama dari program ini.

Apakah saya melewatkan pengorbanan besar di sini? Apakah ada Gotcha yang tidak saya pertimbangkan?

Chris Travers
sumber
1
Diposting silang ke milis pgsql-general. Lihat utas dimulai di sini .
Craig Ringer

Jawaban:

17

Saya pikir Anda sedang mengkonfigurasi otentikasi dan otorisasi .

Saya sepenuhnya setuju bahwa menjaga model keamanan dalam DB adalah bijaksana, terutama karena LedgerSMB dirancang dengan akses dari banyak klien. Kecuali Anda berencana untuk pergi 3-tier dengan lapisan middleware itu membuat sempurna akal untuk memiliki pengguna sebagai peran database, terutama untuk sesuatu seperti sebuah aplikasi akuntansi.

Ini tidak berarti Anda harus mengautentikasi pengguna terhadap database menggunakan metode otentikasi yang didukung PostgreSQL. Pengguna, peran, dan hibah basis data Anda hanya dapat digunakan untuk otorisasi jika Anda mau.

Inilah cara kerjanya untuk web ui misalnya:

  • janeterhubung ke server web ui dan diautentikasi menggunakan metode apa pun yang diinginkan, katakanlah HTTPS X.509 sertifikat tangan klien dan DIGEST auth. Server sekarang memiliki koneksi dari pengguna yang diterimanya benar-benar jane.

  • Server terhubung ke PostgreSQL menggunakan nama pengguna / kata sandi tetap (atau Kerberos atau apa pun yang Anda suka), mengautentikasi diri ke server db sebagai pengguna webui. Server db percaya webuiuntuk mengotentikasi penggunanya sehingga webuitelah diberikan yang sesuai GRANT(lihat di bawah).

  • Pada koneksi yang digunakan server SET ROLE jane;untuk mengasumsikan tingkat otorisasi pengguna jane. Sampai RESET ROLE;atau yang lain SET ROLEdijalankan, koneksi beroperasi dengan hak akses yang sama seperti janedan SELECT current_user()dll akan melaporkan jane.

  • Server mempertahankan hubungan antara koneksi database yang memiliki SET ROLEke janedan sesi web untuk pengguna jane, tidak memungkinkan koneksi PostgreSQL untuk digunakan oleh koneksi lain dengan pengguna lain tanpa baru SET ROLEperalihan.

Anda sekarang mengautentikasi di luar server, tetapi mempertahankan otorisasi di server. Pg perlu tahu apa yang ada pengguna, tetapi tidak perlu kata sandi atau metode otentikasi untuk mereka.

Lihat:

Detail

Server webui mengontrol menjalankan kueri, dan itu tidak akan membiarkan janemenjalankan SQL mentah (saya harap!) Jadi janetidak bisa RESET ROLE; SET ROLE special_admin_user;melalui web ui. Untuk keamanan tambahan, saya akan menambahkan filter pernyataan ke server yang menolak SET ROLEdan RESET ROLEkecuali jika koneksi itu masuk atau memasuki kumpulan koneksi yang belum ditetapkan.

Anda masih bebas menggunakan otentikasi langsung ke Pg di klien lain; Anda dapat mencampur dan mencocokkan secara bebas. Anda hanya perlu GRANTsatu webuipengguna hak untuk SET ROLEuntuk pengguna yang dapat log in melalui web dan kemudian memberikan para pengguna setiap yang normal CONNECThak, password, dll yang Anda inginkan. Jika Anda ingin membuatnya hanya web, hak REVOKEmereka CONNECTpada database (dan dari public).

Untuk mempermudah pemisahan otentikasi / otorisasi, saya memiliki peran khusus assume_any_useryang harus saya GRANTgunakan untuk setiap pengguna yang baru dibuat. Saya kemudian GRANT assume_any_usermenggunakan nama pengguna asli yang digunakan oleh hal-hal seperti front-end web tepercaya, memberi mereka hak untuk menjadi pengguna yang mereka sukai.

Sangat penting untuk membuat assume_any_usersebuah NOINHERITperan, sehingga webuipengguna atau apa pun tidak memiliki privilges dengan diri dan hanya dapat bertindak pada database setelah itu SET ROLEuntuk pengguna nyata. Dalam kondisi apa pun, webuipemilik superuser atau DB tidak boleh .

Jika Anda koneksi pooling, Anda dapat menggunakan SET LOCAL ROLEuntuk mengatur peran hanya dalam transaksi, sehingga Anda dapat mengembalikan koneksi ke pool setelah COMMITatau ROLLBACK. Waspadai itu RESET ROLEmasih berfungsi, jadi masih tidak aman untuk membiarkan klien menjalankan SQL apa pun yang mereka inginkan.

SET SESSION AUTHORIZATIONadalah versi terkait tetapi lebih kuat dari perintah ini. Itu tidak memerlukan peran peran, tapi itu perintah superuser saja. Anda tidak ingin ui web Anda terhubung sebagai superuser. Itu bisa dibalik dengan RESET SESSION AUTHORIZATION, SET SESSION AUTHORIZATION DEFAULTatau SET SESSION AUTHORIZATION theusernameuntuk mendapatkan kembali hak pengguna super sehingga bukan penghalang keamanan yang menjatuhkan hak istimewa juga.

Perintah yang berfungsi seperti SET SESSION AUTHORIZATIONtetapi tidak dapat dipulihkan dan akan bekerja jika Anda adalah anggota peran tetapi bukan superuser akan bagus. Pada titik ini tidak ada satu, tetapi Anda masih dapat memisahkan otentikasi dan otorisasi dengan cukup baik jika Anda berhati-hati.

Contoh dan penjelasan

CREATE ROLE dbowner NOLOGIN;
CREATE TABLE test_table(x text);
INSERT INTO test_table(x) VALUES ('bork');
ALTER TABLE test_table OWNER TO dbowner;

CREATE ROLE assume_any_user NOINHERIT NOLOGIN;
CREATE ROLE webui LOGIN PASSWORD 'somepw' IN ROLE assume_any_user;

CREATE ROLE jane LOGIN PASSWORD 'somepw';
GRANT jane TO assume_any_user;
GRANT ALL ON TABLE test_table TO jane;

CREATE ROLE jim LOGIN PASSWORD 'somepw';
GRANT jim TO assume_any_user;

Sekarang terhubung sebagai webui. Perhatikan bahwa Anda tidak dapat melakukan apapun untuk test_tabletetapi Anda bisa SET ROLE untuk janedan kemudian Anda dapat mengakses test_table:

$ psql -h 127.0.0.1 -U webui regress
Password for user webui:

regress=> SELECT session_user, current_user;
 session_user | current_user 
--------------+--------------
 webui        | webui
(1 row)



regress=> SELECT * FROM test_table;
ERROR:  permission denied for relation test_table

regress=> SET ROLE jane;
SET

regress=> SELECT session_user, current_user;
 session_user | current_user 
--------------+--------------
 webui        | jane
(1 row)

regress=> SELECT * FROM test_table;
  x   
------
 bork
(1 row)

Perhatikan itu webui bisa SET ROLE to jim, bahkan ketika sudah SET ROLEd to janedan meskipun janebelum memiliki GRANThak untuk mengambil peran jim. SET ROLEmenetapkan ID pengguna efektif Anda, tetapi itu tidak menghapus kemampuan Anda untuk SET ROLEperan lain, itu adalah properti dari peran yang Anda hubungkan, bukan peran efektif Anda saat ini. Akibatnya Anda harus hati-hati mengontrol akses ke SET ROLEdan RESET ROLEperintah. Ada, AFAIK, tidak ada cara untuk secara permanen SET ROLEuntuk koneksi, benar-benar menjadi pengguna target, meskipun tentu akan menyenangkan untuk dimiliki.

Membandingkan:

$ psql -h 127.0.0.1 -U webui regress
Password for user webui:

regress=> SET ROLE jane;
SET

regress=> SET ROLE jim;
SET
regress=> SELECT session_user, current_user;
 session_user | current_user 
--------------+--------------
 webui        | jim
(1 row)

untuk:

$ psql -h 127.0.0.1 -U jane regress
Password for user jane:

regress=> SET ROLE webui;
ERROR:  permission denied to set role "webui"
regress=> SET ROLE jim;
ERROR:  permission denied to set role "jim"

Ini berarti bahwa SET ROLEtidak persis sama dengan masuk sebagai peran yang diberikan, sesuatu yang harus Anda ingat.

webuitidak bisa SET ROLEuntuk dbownerkarena belum GRANTed yang tepat:

regress=> SET ROLE dbowner;
ERROR:  permission denied to set role "dbowner"

jadi dengan sendirinya itu tidak berdaya, itu hanya dapat mengasumsikan hak-hak pengguna lain dan hanya ketika para pengguna memiliki akses web diaktifkan.

Craig Ringer
sumber
1
tapi Anda mungkin ingin melihat cara pgbouncerkerjanya untuk beberapa detail.
Craig Ringer
2
Oh, DISCARD ALLadalah cara lain untuk hak yang akan dikembalikan ke default. Saya benar-benar berharap Pg punya SET ROLE NORESETatau serupa ...
Craig Ringer