come proteggere una porta PostgreSQL aperta


29

Quindi, questa è la situazione. Sembra che abbiamo bisogno di avere una porta TCP 5432 aperta al mondo, dove un cliente ha accesso al suo database PostgreSQL.

Per ovvie ragioni, non possiamo dire solo "no", solo come ultima risorsa.

Quali sono i maggiori problemi? Come posso difendere la nostra infrastruttura?

Comunque: perché non dovrebbe essere aperto al mondo? Penso che forse sia più sicuro di un server FTP di 20 anni non mantenuto.

PS VPN non è ok. Forse un po 'di crittografia (se posso dargli un URL di connessione JDBC che funziona ).


4
I tunnel SSH non sono un'opzione? Questo articolo informativo utilizza PostgreSQL come esempio. È possibile fornire al cliente un client SSH preconfigurato per semplificare la connessione.
Lucifer Sam,

@LuciferSam No. Il db verrà utilizzato da un'applicazione java sviluppata internamente su circa 100 macchine aziendali. Il nostro unico modo per configurarli è fornire un URL di connessione jdbc alla loro amministrazione localnet, qualsiasi altro è molto problematico.

@milkman cosa fa l'app? forse potrebbe invece interrogare un server RESTful? Ovviamente, passare SQL a REST non guadagna nulla, ma supponendo che sia CRUD ..
tedder42

@ tedder42 Manipola il database del CMS degli utenti, che è ospitato anche da noi. Non abbiamo il permesso di cambiarne la fonte.

Risposte:


41

Richiede SSL, mantieni SELinux acceso, monitora i log e usa una versione PostgreSQL corrente .

Lato server

Richiedi SSL

Nel postgresql.confset ssl=one assicurati di avere il file di chiavi e il file di certificato installati correttamente (vedere i documenti e i commenti in postgresql.conf).

Potrebbe essere necessario acquistare un certificato da un'autorità di certificazione se si desidera che sia attendibile dai client senza un'installazione speciale sul client.

In pg_hba.confuso qualcosa come:

hostssl theuser thedatabase 1.2.3.4/32 md5

... possibilmente con "tutto" per l'utente e / o il database e possibilmente con un filtro dell'indirizzo IP di origine più ampio.

Limitare gli utenti che possono accedere, negare l'accesso remoto da superutente

Non consentire "tutto" agli utenti, se possibile; non si desidera consentire gli accessi da superutente in remoto se è possibile evitarne la necessità.

Limitare i diritti degli utenti

Limitare i diritti degli utenti che possono accedere. Non concederli CREATEDBo CREATEUSERdiritti.

REVOKEil CONNECTdiritto PUBLICsu tutti i tuoi database, quindi restituiscilo solo agli utenti / ruoli che dovrebbero essere in grado di accedere a quel database. (Raggruppare gli utenti in ruoli e concedere diritti ai ruoli, anziché direttamente ai singoli utenti).

Assicurarsi che gli utenti con accesso remoto possano connettersi solo ai DB di cui hanno bisogno e disporre solo dei diritti su schemi, tabelle e colonne di cui hanno effettivamente bisogno. Questa è una buona pratica anche per gli utenti locali, è solo una sicurezza ragionevole.

Configurazione del client

In PgJDBC, passa il parametrossl=true :

Per indicare al driver JDBC di provare a stabilire una connessione SSL, è necessario aggiungere il parametro URL di connessione ssl = true.

... e installa il certificato del server nel truststore del client, oppure usa un certificato del server considerato attendibile da una delle autorità di certificazione nel truststore incorporato di Java se non desideri che l'utente debba installare il certificato.

Azione in corso

Ora assicurati di mantenere aggiornato PostgreSQL . PostgreSQL ha avuto solo un paio di buchi di sicurezza pre-autorizzazione, ma questo è più di zero, quindi tieniti aggiornato. Dovresti comunque, le correzioni dei bug sono cose carine da avere.

Aggiungi un firewall davanti se ci sono blocchi / regioni di grandi dimensioni da cui sai di non aver mai bisogno di accedere.

Registra connessioni e disconnessioni (vedi postgresql.conf). Log query se pratico. Esegui un sistema di rilevamento delle intrusioni o fail2ban o simile di fronte, se pratico. Per fail2ban con Postgres, c'è un comodo how-to qui

Monitorare i file di registro.

Paranoia bonus

Passaggi extra a cui pensare ...

Richiedi certificati client

Se lo si desidera, è possibile utilizzare anche pg_hba.confper richiedere che il client presenti un certificato client X.509 considerato attendibile dal server. Non è necessario utilizzare la stessa CA del cert del server, è possibile farlo con una CA openssl homebrew. Un utente JDBC deve importare il certificato client nel proprio keytoolarchivio chiavi Java e possibilmente configurare alcune proprietà del sistema JSSE in modo che punti Java al proprio archivio chiavi, quindi non è totalmente trasparente.

Metti in quarantena l'istanza

Se vuoi essere davvero paranoico, esegui l'istanza per il client in un container / VM separato, o almeno con un altro account utente, con solo il database oi database richiesti.

In questo modo se compromettono l'istanza PostgreSQL non otterranno più.

Usa SELinux

Non avrei dovuto dirlo, ma ...

Esegui una macchina con supporto SELinux come RHEL 6 o 7 e non spegnere SELinux o impostarlo in modalità permissiva . Mantieni la modalità di applicazione.

Utilizzare una porta non predefinita

La sicurezza solo per l' oscurità è stupidità. La sicurezza che usa un po 'di oscurità dopo aver fatto le cose sensibili probabilmente non farà male.

Esegui Pg su una porta non predefinita per rendere la vita un po 'più difficile per gli attaccanti automatizzati.

Metti un proxy davanti

Puoi anche eseguire PgBouncer o PgPool-II davanti a PostgreSQL, fungendo da pool di connessioni e proxy. In questo modo è possibile lasciare che il proxy gestisca SSL, non l'host del database reale. Il proxy può essere su una macchina o macchina virtuale separata.

L'uso dei proxy di pool di connessioni è generalmente una buona idea con PostgreSQL, a meno che l'app client non abbia già un pool integrato. La maggior parte dei server di applicazioni Java, Rails, ecc. Hanno un pool incorporato. Anche allora, un proxy di pooling lato server è nella peggiore delle ipotesi innocuo.


3
Se il client ha un $ IP statico, lo consenti anche solo attraverso il firewall a $ port.
user9517 supporta GoFundMonica il

Grazie mille! Pgjdbc ha questo parametro, ma posso dargli solo un url di connessione jdbc e non sono sicuro che funzionerà con la sua applicazione java (proprietaria, indebitabile). Ok, in caso contrario farò una nuova domanda. Grazie la tua risposta dettagliata!

1
@lesto In realtà, penso che esporre una VPN aumenti enormemente la superficie di attacco rispetto a un solo servizio limitato. Le persone dimenticano che la VPN diventa quindi un canale di attacco per qualsiasi malware sui computer remoti per perforare tutta la sicurezza perimetrale e arrivare alle viscere della rete. Li trovo accettabili solo se si collegano a una DMZ che li considera altrettanto tossici come gli host di Internet.
Craig Ringer,

1
@CraigRinger Non sto dicendo di rimuovere il resto della protezione, ma di incapsulare il servizio in VPN
Lesto,

1
@lesto Certo, d'accordo, una VPN può essere un utile livello extra se non viene trattata come Magic Security Sauce come sfortunatamente fanno molti amministratori.
Craig Ringer,

2

Una semplice estensione dell'impressionante piano d'azione Craigs:

Forse l'utente utilizza solo un set relativamente limitato di provider di rete (ad esempio, il suo provider di rete mobile durante lo spostamento, la sua rete via cavo da casa e l'IP in uscita dal lavoro).

La maggior parte dei provider di rete ha molti IP, ma non molte sottoreti. Quindi, puoi fornire un filtro iptables, che limita l'accesso postgresql ai segmenti di rete utilizzati dal tuo cliente. Ciò ha notevolmente ridotto le possibilità di attacco di fonti di disturbo della rete selezionate casualmente.

Un semplice scenario di supporto:

  1. Il tuo cliente ti chiama "Non riesco ad accedere" .
  2. Lo scopri con un tcpdump -i eth0 -p tcp port 5432comando, da dove viene.
  3. Con un whois 1.2.3.4è possibile ottenere l'indirizzo IP utilizzato da questo IP. Ad esempio, può essere 1.2.3.0/24.
  4. Con un iptables -A INPUT -s 1.2.3.0/24 -p tcp --dport 5432 -j ACCEPT(o qualcosa di simile) si consentono le connessioni tcp con la sua nuova sottorete.

Esiste un ottimo script perl chiamato uifche può fornire set di regole iptables dichiarabili permanenti e intuitivi. (Google per "uif iptables").


1
Un'idea interessante, ma sembra un po 'fragile.
nishantjr,

@nishantjr Naturalmente non è una soluzione autonoma, solo una possibilità per migliorare le cose.
Peter dice di reintegrare Monica il

Un approccio più pratico potrebbe essere quello di autorizzare i singoli ISP e / o paesi, per i modi per farlo vedere ad esempio stackoverflow.com/questions/16617607/…
Josip Rodin,

1

Ecco una configurazione Fail2ban abbastanza semplice per PostgreSQL basata sull'HOWTO collegato sopra ma ottimizzata per funzionare effettivamente con i pacchetti Ubuntu, rilevare un'altra condizione di errore e saltare vari messaggi di debug per renderlo più veloce:

/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

1

Fail2ban è uno strumento potente, ma non fidarti che un filtro funzionerà così com'è. Testa i filtri usando lo strumento failregex e ricorda di sfuggire alle virgolette (ovvero "admin" sarebbe \ "admin \"). Ad esempio, testare la seguente riga failregex del filtro dal mio /etc/log/postgresql/postgresql-9.3-main.log non ha funzionato per me.

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

Quanto sopra mi ha dato

Failregex: 0 totali

Ho dovuto aggiornare il failregex in modo che corrispondesse al formato del registro.

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

Questo mi ha dato un risultato positivo.

Failregex: 1 totale

Il test fail2ban-regex può essere implementato anche su interi file di registro.

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

Quanto sopra mi ha dato il seguente risultato positivo con il failregex aggiornato.

Failregex: 169 totali

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.