Skip to content

Consentire ai processi non root di eseguire il binding alle porte 80 e 443?

Questa è la risposta più completa che troverai da condividere, ma prima guardala attentamente e vedi se può essere adattata al tuo progetto.

Soluzione:

Non sono sicuro di cosa si riferiscano le altre risposte e i commenti qui presenti. Questo è possibile piuttosto facilmente. Esistono due opzioni, che consentono entrambe di accedere alle porte a bassa numerazione senza dover elevare il processo a root:

Opzione 1: utilizzare CAP_NET_BIND_SERVICE per concedere l'accesso alle porte a basso numero a un processo:

In questo modo è possibile concedere l'accesso permanente a un binario specifico per effettuare il bind alle porte a basso numero tramite il parametro setcap tramite il comando setcap :

sudo setcap CAP_NET_BIND_SERVICE=+eip /path/to/binary

Per maggiori dettagli sulla parte e/i/p, vedere cap_from_text.

Dopo aver fatto questo, /path/to/binary sarà in grado di effettuare il binding alle porte a basso numero. Si noti che è necessario utilizzare setcapsul binario stesso piuttosto che su un link simbolico.

Opzione 2: utilizzare authbind per concedere l'accesso una tantum, con un controllo più preciso su utenti/gruppi/porta:

Il authbind (pagina man) esiste proprio per questo.

  1. Installare authbind usando il vostro gestore di pacchetti preferito.

  2. Configuratelo per garantire l'accesso alle porte pertinenti, ad esempio per consentire 80 e 443 a tutti gli utenti e gruppi:

    sudo touch /etc/authbind/byport/80
    sudo touch /etc/authbind/byport/443
    sudo chmod 777 /etc/authbind/byport/80
    sudo chmod 777 /etc/authbind/byport/443
    
  3. Ora eseguite il comando tramite authbind (specificando facoltativamente --deep o altri argomenti, vedere la pagina man):

    authbind --deep /path/to/binary command line args
    

    Ad esempio

    authbind --deep java -jar SomeServer.jar
    

Entrambe le opzioni hanno lati positivi e negativi. L'opzione 1 concede fiducia al file binario ma non fornisce alcun controllo sull'accesso per porta. L'opzione 2 concede la fiducia al binario utente/gruppo e fornisce il controllo sull'accesso per porta, ma le versioni precedenti supportavano solo IPv4 (da quando ho scritto questo articolo sono state rilasciate nuove versioni con supporto IPv6).

Dale Hagglund ha ragione. Quindi dirò la stessa cosa ma in modo diverso, con alcune specifiche ed esempi ☺.

La cosa giusta da fare nel mondo Unix e Linux è:

  • avere un programma piccolo, semplice, facilmente verificabile, che viene eseguito come superutente e che vincola il socket di ascolto;
  • avere un altro piccolo programma, semplice e facilmente verificabile, che elimina i privilegi, generato dal primo programma;
  • avere la parte principale del servizio, in un programma separato terzo eseguito sotto un account non superutente e caricato a catena dal secondo programma, aspettandosi di ereditare semplicemente un descrittore di file aperto per il socket.

Avete un'idea sbagliata di dove sia l'alto rischio. Il rischio elevato è in nel leggere dalla rete e nell'agire su ciò che viene letto non nei semplici atti di apertura di un socket, di collegamento a una porta e di chiamata a listen(). È la parte di un servizio che esegue la comunicazione vera e propria a essere ad alto rischio. Le parti che aprono, bind()e listen()e persino (in una certa misura) la parte che accepts()non sono ad alto rischio e possono essere eseguiti sotto l'egida del superutente. Non utilizzano e non agiscono su (con l'eccezione degli indirizzi IP di origine nella sezione accept() caso) dati che sono sotto il controllo di estranei non fidati attraverso la rete.

Ci sono molti modi per farlo.

inetd

Come afferma Dale Hagglund, il vecchio "superserver di rete" inetd fa questo. L'account sotto il quale viene eseguito il processo di servizio è una delle colonne di inetd.conf. Non separa la parte di ascolto e la parte di eliminazione dei privilegi in due programmi separati, piccoli e facilmente verificabili, ma separa il codice di servizio principale in un programma separato, exec()in un processo di servizio che viene generato con un descrittore di file aperto per il socket.

La difficoltà di auditing non è un problema, dato che si deve controllare solo un programma. inetdIl problema principale di inetd non è tanto l'auditing, quanto piuttosto il fatto che non fornisce un semplice controllo dei servizi di runtime a grana fine, rispetto a strumenti più recenti.

UCSPI-TCP e daemontools

I pacchetti UCSPI-TCP e daemontools di Daniel J. Bernstein sono stati progettati per fare questo insieme. In alternativa si può usare il set di strumenti daemontools-encore di Bruce Guenter, in gran parte equivalente.

Il programma per aprire il descrittore di file del socket e fare il bind alla porta locale privilegiata è tcpserver, da UCSPI-TCP. Esegue entrambe le operazioni di listen() e il accept().

tcpserver e poi genera un programma di servizio che si priva dei privilegi di root (perché il protocollo da servire prevede di iniziare come superutente e poi di "loggarsi", come avviene, ad esempio, con un demone FTP o SSH) oppure setuidgid che è un programma autonomo, piccolo e facilmente verificabile, che si limita a togliere i privilegi e poi a caricare a catena il programma di servizio vero e proprio (nessuna parte del quale viene quindi eseguita con i privilegi di superutente, come nel caso, ad esempio, di qmail-smtpd).

),qmail-smtpd).

Un servizio run potrebbe essere un esempio (questo per dummyidentd per fornire il servizio null IDENT):

#!/bin/sh -e
exec 2>&1
exec 
tcpserver 0 113 
setuidgid nobody 
dummyidentd.pl

nosh

Il mio pacchetto nosh è progettato per fare questo. Ha un piccolo file setuidgid proprio come gli altri. Una piccola differenza è che è utilizzabile con systemd-come i servizi "LISTEN_FDS" e con i servizi UCSPI-TCP, per cui il tradizionale sistema di tcpserver è sostituito da due programmi separati: tcp-socket-listen e tcp-socket-accept.

Anche in questo caso, le utilità a scopo singolo si riproducono e si caricano a catena l'una con l'altra. Un'interessante stranezza del progetto è che si possono abbandonare i privilegi di superutente dopo il passaggio a listen() ma prima ancora di accept(). Ecco un run per qmail-smtpd che fa esattamente questo:

#!/bin/nosh
fdmove -c 2 1
clearenv --keep-path --keep-locale
envdir env/
softlimit -m 70000000
tcp-socket-listen --combine4and6 --backlog 2 ::0 smtp
setuidgid qmaild
sh -c 'exec 
tcp-socket-accept -v -l "${LOCAL:-0}" -c "${MAXSMTPD:-1}" 
ucspi-socket-rules-check 
qmail-smtpd 
'

I programmi che vengono eseguiti sotto l'egida del superutente sono i piccoli strumenti per il caricamento della catena dei servizi fdmove, clearenv, envdir, softlimit, tcp-socket-listene setuidgid. Al punto che sh viene avviato, il socket è aperto e legato alla cartella smtp e il processo non ha più i privilegi di superutente.

s6, s6-networking ed execline

I pacchetti s6 e s6-networking di Laurent Bercot sono stati progettati per svolgere questo compito insieme. I comandi sono strutturalmente molto simili a quelli di daemontools e UCSPI-TCP.

run sarebbero più o meno gli stessi, tranne che per la sostituzione di s6-tcpserver per tcpserver e s6-setuidgid per setuidgid. Tuttavia, si potrebbe anche scegliere di utilizzare contemporaneamente il set di strumenti execline di M. Bercot.

Ecco un esempio di servizio FTP, leggermente modificato dall'originale di Wayne Marshall, che utilizza execline, s6, s6-networking e il programma server FTP di publicfile:

#!/command/execlineb -PW
multisubstitute {
    define CONLIMIT 41
    define FTP_ARCHIVE "/var/public/ftp"
}
fdmove -c 2 1
s6-envuidgid pubftp 
s6-softlimit -o25 -d250000 
s6-tcpserver -vDRH -l0 -b50 -c ${CONLIMIT} -B '220 Features: a p .' 0 21 
ftpd ${FTP_ARCHIVE}

ipsvd

ipsvd di Gerrit Pape è un altro insieme di strumenti che funziona sulla falsariga di ucspi-tcp e s6-networking. Gli strumenti sono chpst e tcpsvd questa volta, ma fanno la stessa cosa e il codice ad alto rischio che si occupa della lettura, dell'elaborazione e della scrittura delle cose inviate in rete da client non attendibili è ancora in un programma separato.

Ecco l'esempio di M. Pape di esecuzione di fnord in un programma run script:

#!/bin/sh
exec 2>&1
cd /public/10.0.5.4
exec 
chpst -m300000 -Uwwwuser 
tcpsvd -v 10.0.5.4 443 sslio -v -unobody -//etc/fnord/jail -C./cert.pem 
fnord

systemd

systemd, il nuovo sistema di supervisione dei servizi e di init che si trova in alcune distribuzioni Linux, è destinato a fare ciò che inetdpuò fare. Tuttavia, non utilizza una suite di piccoli programmi autonomi. È necessario controllare systemd nella sua interezza, purtroppo.

Con systemd si creano file di configurazione per definire un socket che systemd ascolta e un servizio che systemd avvia. Il file "unit" del servizio ha delle impostazioni che permettono di avere un grande controllo sul processo del servizio, compreso l'utente con cui viene eseguito.

Con l'utente impostato come non superutente, systemd esegue tutto il lavoro di apertura del socket, il binding con una porta e la chiamata a listen() (e, se necessario, accept()) nel processo #1 come superutente, mentre il processo di servizio che genera viene eseguito senza privilegi di superutente.

Io ho un approccio piuttosto diverso. Volevo usare la porta 80 per un server node.js. Non ho potuto farlo perché Node.js è stato installato per un utente non-sudo. Ho provato a usare i link simbolici, ma non ha funzionato.

Poi ho capito che posso inoltrare le connessioni da una porta a un'altra. Così ho avviato il server sulla porta 3000 e ho impostato un port forward dalla porta 80 alla porta 3000.

Questo link fornisce i comandi effettivi che possono essere usati per fare questo. Ecco i comandi -

localhost/loopback

sudo iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 3000

esterno

sudo iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 3000

Ho usato il secondo comando e ha funzionato. Quindi penso che questa sia una via di mezzo per non permettere ai processi utente di accedere direttamente alle porte inferiori, ma per consentire loro di accedervi utilizzando il port-forwarding.

Ti mostriamo recensioni e valutazioni

Se ti è piaciuto il nostro lavoro, sei libero di lasciare una nota su ciò che ti è piaciuto di questo articolo.



Utilizzate il nostro motore di ricerca

Ricerca
Generic filters

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.