cara mengamankan port PostgreSQL terbuka

29

Jadi, inilah situasinya. Tampaknya kita perlu memiliki port TCP terbuka 5432 ke dunia, di mana pelanggan memiliki akses ke database PostgreSQL-nya.

Untuk alasan yang jelas, kita tidak bisa mengatakan "tidak", hanya sebagai pilihan terakhir.

Apa masalah terbesarnya? Bagaimana saya bisa mempertahankan infrastruktur kami?

Ngomong-ngomong: mengapa tidak dibuka untuk dunia? Saya pikir, mungkin lebih aman daripada server FTP yang berumur 20 tahun yang tidak dirawat.

PS VPN tidak ok. Beberapa enkripsi mungkin (jika saya bisa memberinya URL koneksi JDBC yang berfungsi ).

Josip Rodin
sumber
4
Terowongan SSH bukan pilihan? Artikel how-to ini benar-benar menggunakan PostgreSQL sebagai contoh. Anda bisa memberi pelanggan klien SSH yang sudah dikonfigurasi sebelumnya agar mudah terhubung.
Lucifer Sam
@LuciferSam No. db akan digunakan oleh aplikasi java yang dikembangkan sendiri di sekitar 100 mesin perusahaan. Satu-satunya cara kami untuk mengonfigurasinya adalah dengan memberikan url koneksi jdbc ke administrasi lokal mereka, yang lain sangat-sangat bermasalah.
@ Milkman apa yang dilakukan aplikasi? mungkin itu bisa meminta server yang tenang bukan? Jelas, meneruskan SQL ke REST tidak mendapatkan apa-apa, tetapi dengan asumsi itu CRUD ..
tedder42
@ tedder42 Ini memanipulasi basis data pengguna CMS, yang juga dihosting oleh kami. Kami tidak memiliki izin untuk mengubah sumbernya.

Jawaban:

41

Wajibkan SSL, aktifkan SELinux, monitor log, dan gunakan versi PostgreSQL saat ini .

Sisi server

Membutuhkan SSL

Dalam postgresql.confset ssl=ondan pastikan Anda telah menginstal keyfile dan certfile Anda dengan tepat (lihat dokumen dan komentar di postgresql.conf).

Anda mungkin perlu membeli sertifikat dari CA jika Anda ingin dipercaya oleh klien tanpa pengaturan khusus pada klien.

Dalam pg_hba.confmenggunakan sesuatu seperti:

hostssl theuser thedatabase 1.2.3.4/32 md5

... mungkin dengan "semua" untuk pengguna dan / atau basis data, dan mungkin dengan filter alamat IP sumber yang lebih luas.

Batasi pengguna yang dapat masuk, menolak masuk superuser jarak jauh

Jangan izinkan "semua" untuk pengguna jika memungkinkan; Anda tidak ingin mengizinkan login pengguna super jarak jauh jika Anda dapat menghindari kebutuhan untuk itu.

Batasi hak pengguna

Batasi hak-hak pengguna yang bisa masuk. Jangan beri mereka CREATEDBatau CREATEUSERhak.

REVOKEyang CONNECTbenar dari PUBLICpada semua database Anda, kemudian memberikannya kembali kepada hanya pengguna / peran yang harus dapat mengakses bahwa database. (Kelompokkan pengguna ke dalam peran dan berikan hak untuk peran, alih-alih langsung ke pengguna individu).

Pastikan pengguna dengan akses jarak jauh hanya dapat terhubung ke DB yang mereka butuhkan, dan hanya memiliki hak untuk skema, tabel, dan kolom di dalam yang sebenarnya mereka butuhkan. Ini adalah praktik yang baik untuk pengguna lokal juga, itu hanya keamanan yang masuk akal.

Pengaturan klien

Di PgJDBC, berikan parameterssl=true :

Untuk menginstruksikan driver JDBC untuk mencoba dan membangun koneksi SSL Anda harus menambahkan parameter URL koneksi ssl = true.

... dan instal sertifikat server di truststore klien, atau gunakan sertifikat server yang dipercaya oleh salah satu CA di truststore bawaan Java jika Anda tidak ingin pengguna harus menginstal sertifikat.

Tindakan yang sedang berlangsung

Sekarang pastikan Anda selalu memperbarui PostgreSQL . PostgreSQL hanya memiliki beberapa celah keamanan pra-auth, tapi itu lebih dari nol, jadi tetap up to date. Anda seharusnya tetap, perbaikan bug adalah hal yang baik untuk dimiliki.

Tambahkan firewall di depan jika ada netblock / daerah besar yang Anda tahu tidak perlu Anda akses.

Log koneksi dan pemutusan (lihat postgresql.conf). Catat kueri jika praktis. Jalankan sistem deteksi intrusi atau fail2ban atau serupa di depan jika praktis. Untuk fail2ban dengan postgres, ada caranya di sini

Pantau file log.

Paranoia bonus

Langkah ekstra untuk dipikirkan ...

Membutuhkan sertifikat klien

Jika Anda ingin, Anda juga dapat menggunakan pg_hba.confagar klien menghadirkan sertifikat klien X.509 yang dipercaya oleh server. Tidak perlu menggunakan CA yang sama dengan server cert, Anda dapat melakukan ini dengan homebrew openssl CA. Seorang pengguna JDBC perlu mengimpor sertifikat klien ke Java Keystore mereka dengan keytooldan mungkin mengkonfigurasi beberapa properti sistem JSSE untuk mengarahkan Java di keystore mereka, sehingga tidak sepenuhnya transparan.

Karantina contohnya

Jika Anda ingin menjadi benar-benar paranoid, jalankan instance untuk klien dalam wadah terpisah / VM, atau setidaknya di bawah akun pengguna yang berbeda, hanya dengan database yang dibutuhkan.

Dengan begitu jika mereka mengkompromikan instance PostgreSQL, mereka tidak akan melanjutkan.

Gunakan SELinux

Aku seharusnya tidak mengatakan ini, tapi ...

Jalankan mesin dengan dukungan SELinux seperti RHEL 6 atau 7, dan jangan matikan SELinux atau setel ke mode permisif . Simpan dalam mode menegakkan.

Gunakan port non-default

Keamanan hanya dengan ketidakjelasan adalah kebodohan. Keamanan yang menggunakan sedikit ketidakjelasan setelah Anda melakukan hal-hal yang masuk akal mungkin tidak akan sakit.

Jalankan Pg pada port non-default untuk membuat hidup sedikit lebih sulit bagi penyerang otomatis.

Letakkan proxy di depan

Anda juga dapat menjalankan PgBouncer atau PgPool-II di depan PostgreSQL, bertindak sebagai kumpulan koneksi dan proksi. Dengan begitu Anda dapat membiarkan proxy menangani SSL, bukan host database asli. Proxy dapat berada di VM atau mesin yang terpisah.

Penggunaan proksi penyatuan koneksi umumnya merupakan ide yang bagus dengan PostgreSQL, kecuali jika aplikasi klien sudah memiliki pool bawaan. Sebagian besar server aplikasi Java, Rails, dll memiliki pooling bawaan. Bahkan kemudian, proxy pooling sisi server pada terburuk tidak berbahaya.

Craig Ringer
sumber
3
Jika klien memiliki $ IP statis hanya mengizinkannya melalui firewall ke $ port juga.
user9517 mendukung GoFundMonica
Terima kasih banyak! Pgjdbc memiliki param ini, tetapi saya hanya bisa memberinya url koneksi jdbc, dan saya tidak yakin apakah itu akan berfungsi dengan aplikasi java-nya (proprietary, undebuggable). Ok, kalau tidak saya akan mengajukan pertanyaan baru. Terima kasih jawaban terinci Anda!
1
@ Sebenarnya, saya pikir mengekspos VPN secara besar-besaran meningkatkan permukaan serangan dibandingkan dengan hanya satu layanan terbatas. Orang-orang lupa bahwa VPN kemudian menjadi saluran serangan untuk setiap malware di mesin jarak jauh untuk menembus semua keamanan perimeter dan sampai ke keberanian jaringan. Saya hanya menemukan mereka dapat diterima jika mereka terhubung ke DMZ yang memperlakukan mereka sama beracunnya dengan host Internet.
Craig Ringer
1
@CraigRinger saya tidak mengatakan untuk menghapus sisa perlindungan, tetapi untuk merangkum layanan ke VPN
Lesto
1
@lesto Tentu, setuju, VPN bisa menjadi lapisan tambahan yang berguna jika tidak diperlakukan sebagai Saus Keamanan Ajaib seperti yang dilakukan banyak admin.
Craig Ringer
2

Perpanjangan sederhana untuk rencana aksi mengesankan Craigs:

Mungkin pengguna hanya menggunakan sejumlah kecil penyedia jaringan (misalnya, penyedia jaringan selulernya saat bergerak, jaringan kabelnya dari rumah dan ip keluar dari tempat kerja).

Sebagian besar penyedia jaringan memiliki banyak IP, tetapi tidak terlalu banyak subnet. Jadi, Anda bisa memberikan filter iptables, yang membatasi akses postgresql ke segmen jaringan yang digunakan oleh pelanggan Anda. Ini sangat mengurangi kemungkinan serangan sumber masalah yang dipilih secara acak dari jaring.

Skenario dukungan sederhana:

  1. Pelanggan Anda memanggil Anda, "Saya tidak bisa masuk" .
  2. Anda mencari tahu dengan tcpdump -i eth0 -p tcp port 5432perintah, dari mana dia berasal.
  3. Dengan whois 1.2.3.4Anda bisa mendapatkan alamat ip yang digunakan oleh ip ini. Misalnya saja bisa 1.2.3.0/24.
  4. Dengan iptables -A INPUT -s 1.2.3.0/24 -p tcp --dport 5432 -j ACCEPT(atau yang serupa) Anda memungkinkan koneksi tcp dengan subnet barunya.

Ada skrip perl yang sangat baik bernama uifyang dapat memberikan iptables dideklarasikan permanen dan intuitif. (Google untuk "uif iptables").

peterh mengatakan mengembalikan Monica
sumber
1
Ide yang menarik, tapi itu terdengar agak rapuh.
nishantjr
@nishantjr Tentu saja ini bukan solusi mandiri, hanya kemungkinan untuk memperbaiki keadaan.
peterh mengatakan mengembalikan Monica
Pendekatan yang lebih praktis mungkin untuk membuat daftar putih masing-masing ISP dan / atau negara, untuk cara-cara ini lihat misalnya stackoverflow.com/questions/16617607/…
Josip Rodin
1

Berikut ini adalah konfigurasi Fail2ban yang cukup sederhana untuk PostgreSQL berdasarkan HOWTO yang ditautkan di atas tetapi disesuaikan untuk benar-benar berfungsi dengan paket Ubuntu, menangkap kondisi kesalahan lain dan melewatkan berbagai pesan debug untuk membuatnya lebih cepat:

/etc/fail2ban/filter.d/local-postgresql.conf:

[Definition]

failregex = <HOST>\(\d+\) FATAL:  password authentication failed for .+$
            <HOST>\(\d+\) FATAL:  no pg_hba.conf entry for host .+$

ignoreregex = duration:

/etc/fail2ban/jail.d/local-postgresql.conf:

[local-postgresql]
enabled  = true
filter   = local-postgresql
action   = iptables[name=PostgreSQL, port=5432, protocol=tcp]
           sendmail-whois[name=PostgreSQL, dest=root@localhost]
logpath  = /var/log/postgresql/postgresql-9.3-main.log
maxretry = 3
Josip Rodin
sumber
1

Fail2ban adalah alat yang ampuh, tetapi jangan percaya bahwa filter akan berfungsi apa adanya. Uji semua filter menggunakan alat failregex , dan ingatlah untuk menghindari tanda kutip (mis. "Admin" adalah \ "admin \"). Sebagai contoh, pengujian baris filter gagalregex berikut dari /etc/log/postgresql/postgresql-9.3-main.log saya tidak berfungsi untuk saya.

fail2ban-regex '2016-09-20 14:30:09 PDT FATAL:  password authentication failed for user "admin"' '<HOST>\(\d+\) FATAL:  password authentication failed for .+$'

Di atas memberi saya

Failregex: 0 total

Saya harus memperbarui failregex agar sesuai dengan format log.

fail2ban-regex '2016-09-20 14:30:09 PDT FATAL:  password authentication failed for user "admin"' 'FATAL:  password authentication failed for user \"<HOST>\"'

Ini memberi saya hasil positif.

Failregex: 1 total

Uji fail2ban-regex juga dapat diterapkan pada seluruh file log.

fail2ban-regex /var/log/postgresql/postgresql-9.3-main.log /etc/fail2ban/filter.d/postgresql.local

Di atas memberi saya hasil positif berikut dengan failregex diperbarui.

Failregex: 169 total

meterales
sumber