Come eseguire un server sulla porta 80 come un normale utente su Linux?


311

Ho cercato su Google una soluzione per un po 'di tempo, ma non sono riuscito a trovare una risposta.

Sono su Ubuntu Linux e voglio eseguire un server sulla porta 80, ma a causa del meccanismo di sicurezza di Ubuntu, ricevo il seguente errore:

java.net.BindException: autorizzazione negata: 80

Penso che dovrebbe essere abbastanza semplice disabilitare questo meccanismo di sicurezza in modo che la porta 80 sia disponibile per tutti gli utenti o assegnare i privilegi richiesti all'utente corrente per accedere alla porta 80.


3
Qual è il problema per eseguire il server su un'altra porta che non è privilegiata? Stai pensando a qualcosa di duro come disabilitare il meccanismo di sicurezza senza fornire almeno una ragione molto seria per eseguire un server su quella porta. Il server è hardcoded per collegarsi alla porta 80? Se è così, buttalo via.
Anonimo il


4
Non puoi. Le porte inferiori a 1024 sono privilegiate e solo root può aprire socket di ascolto su di esse. La cosa appropriata da fare è eliminare le autorizzazioni dopo averlo aperto.
Falcon Momot

2
"Anonimo": gli utenti del mondo sono stati addestrati a cercare determinati servizi in determinati porti. In alcuni casi, è stato standardizzato. Ad esempio, HTTP sulla porta 80 e HTTPS sulla porta 443. È un po 'difficile cambiare gli utenti e gli standard del mondo.

1
@FalconMomot Se le porte inferiori a 1024 sono privilegiate, perché il server Apache non richiede di inserire una password per ottenere i privilegi di root sulla porta 80, e come fanno in questo modo? Penso che l'interrogante voglia sapere come fare le cose in quel modo (sia che sia tecnicamente usato come root o meno). Sentiti libero di dirmi se sbaglio, Deepak Mittal.
Shule,

Risposte:


355

Risposta breve: non puoi. Le porte inferiori a 1024 possono essere aperte solo da root. Come da commento - beh, puoi, usando CAP_NET_BIND_SERVICE , ma quell'approccio, applicato al java bin, farà funzionare qualsiasi programma java con questa impostazione, il che è indesiderabile, se non un rischio per la sicurezza.

La risposta lunga: è possibile reindirizzare le connessioni sulla porta 80 verso un'altra porta che è possibile aprire come utente normale.

Esegui come root:

# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

Dato che i dispositivi di loopback (come localhost) non usano le regole di pre-indirizzamento, se devi usare localhost, ecc., Aggiungi anche questa regola ( grazie a @Francesco ):

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

NOTA: la soluzione di cui sopra non è adatta ai sistemi multiutente, in quanto qualsiasi utente può aprire la porta 8080 (o qualsiasi altra porta alta che si decide di utilizzare), intercettando così il traffico. (Crediti a CesarB ).

MODIFICA: come da domanda di commento - per eliminare la regola sopra:

# iptables -t nat --line-numbers -n -L

Questo produrrà qualcosa di simile:

Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination         
1    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:8080 redir ports 8088
2    REDIRECT   tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80 redir ports 8080

La regola che ti interessa è nr. 2, quindi per eliminarlo:

# iptables -t nat -D PREROUTING 2

13
@Sunny: i voti positivi non sono per la pistola più veloce in Occidente, ma per le migliori risposte. Il tuo è il migliore finora (ho menzionato solo iptables; in realtà hai fornito l'intera riga di comando). L'unica cosa che la mia ha non è la tua avvertenza sul fatto che anche altri utenti siano in grado di collegarsi alla porta 8080.
CesarB,

3
Si noti che questo non funziona con IPv6.
Emmanuel Bourg,

3
Qualcuno potrebbe spiegare come posso rimuovere questa regola in seguito quando voglio? Dopo averlo eseguito, funziona, ma a quanto pare non è una "regola" perché non si presenta quando lo faccio sudo iptables --list. So cosa è e cosa fa iptables, ma non l'ho mai usato prima.
Encoder

4
Grazie per la risposta ... ogni volta che riavvio Ubuntu, questa regola scompare e devo eseguirla di nuovo. C'è un modo per salvarlo per sempre?
Coderji,

4
@Coderji: controlla la sezione "salva" nella documentazione della comunità: help.ubuntu.com/community/IptablesHowTo
Sunny

79

Usa authbind .

Funziona anche con Java se si abilita lo stack solo IPv4 di Java. Io uso:

authbind --deep $JAVA_HOME/bin/java -Djava.net.preferIPv4Stack=true …

4
Se il server è Tomcat, puoi utilizzare authbind automaticamente impostando AUTHBIND=yesin / etc / default / tomcat6
Emmanuel Bourg

Non sono riuscito a farlo funzionare sul server Ubuntu con il pacchetto Java predefinito ...
Ashley,

Nemmeno io, nessuna soluzione nota?
segna il

10
Si noti che è necessario configurare authbindper consentire effettivamente che ciò accada. Dalla pagina man: "/ etc / authbind / byport / port è testato. Se questo file è accessibile per l'esecuzione all'utente chiamante, in base all'accesso (2), è autorizzato il binding alla porta." , Ad esempio per la porta 80, sudo touch /etc/authbind/byport/80 ; sudo chmod 777 /etc/authbind/byport/80. L'installazione iniziale di authbindgeneralmente non ha autorizzazioni preconfigurate.
Jason C

4
Oh nonononononono, non fare mai chmod 777 niente!
Johannes,

57

Se il tuo sistema lo supporta, potresti utilizzare le funzionalità. Vedi le funzionalità man, quella di cui hai bisogno sarebbe CAP_NET_BIND_SERVICE.

Su Debian / Ubuntu più recenti puoi eseguire:

sudo apt-get install libcap2-bin 
sudo setcap 'cap_net_bind_service=+ep' /path/to/program

questo funziona per nodejs: setcap 'cap_net_bind_service = + ep' / usr / bin / nodejs
JasonS

5
Questo. Mi chiedo perché questa risposta non abbia più voti. Molto più semplice dell'opzione iptables imho.
Dominik R,

5
questa è la risposta corretta ed efficiente, tutte le altre risposte causano un calo delle prestazioni o semplicemente iffy / insicure.
OneOfOne,

41

Un'altra soluzione è rendere setuid l'app in modo che possa collegarsi con la porta 80. Come root, procedi come segue

chown root ./myapp
chmod +S ./myapp

Tieni presente che farlo, a meno che non sia stato eseguito correttamente, ti esporrà a potenziali falle di sicurezza, perché la tua app parlerà con la rete e funzionerà con privilegi di root completi. Se prendi questa soluzione, dovresti guardare il codice sorgente di Apache o Lighttpd o qualcosa di simile, in cui usano i privilegi di root per aprire la porta, ma poi immediatamente rinunciare a quei priv e "diventare" un utente con privilegi inferiori in modo che un dirottatore non può assumere il controllo dell'intero computer.

Aggiornamento: come visto in questa domanda , sembra che i kernel Linux dalla 2.6.24 abbiano una nuova capacità che ti consenta di contrassegnare un eseguibile (ma non uno script, ovviamente) come " CAP_NET_BIND_SERVICE". Se installi il pacchetto debian "libcap2-bin", puoi farlo inviando il comando

setcap 'cap_net_bind_service=+ep' /path/to/program

6
Ciò equivale a eseguire come root, a meno che l'app non sappia come eliminare i privilegi.
CesarB,

14
Questo è pericoloso. Ciò significa che qualsiasi richiesta verrà eseguita come root. È per un motivo che anche apache inizia come root da associare, quindi rilascia i privilegi a un altro utente.
Sunny

9
Paul: iptables non è così pericoloso, perché anche se l'app è compromessa, non esporrà il sistema agli attacchi, almeno non con i privilegi di root. L'esecuzione dell'app come root è un'altra storia.
Sunny

1
Il pericolo per iptables è solo se si tratta di un sistema multiutente, come ha detto CesarB, poiché chiunque può legarsi a 8080 e intercettare il traffico.
Sunny

1
lol, adoro come la risposta accettata abbia un -15
Evan Teran,

40

Uso semplicemente Nginx di fronte. Può funzionare anche su localhost.

  • apt-get install nginx

.. o ..

  • pkg_add -r nginx

.. o ciò che si adatta al tuo sistema operativo.

Tutto ciò di cui hai bisogno in nginx.conf, se in esecuzione su localhost, è:

server {
        ascolta 80;
        nome_server some.domain.org;
        Posizione / {
            proxy_set_header Host $ host;
            proxy_set_header X-Real-IP $ remote_addr;
            proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:8081;
        }
}

Mi piace molto questa soluzione.
thomasfedb,

1
Questa è (una delle) soluzioni suggerite dagli stessi JFrog
stolsvik

36

Approccio proposto da Sunny e CesarB:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

funziona bene ma ha un piccolo inconveniente: non impedisce all'utente di connettersi direttamente alla porta 8080 anziché 80.

Considera il seguente scenario quando questo può essere un problema.

Supponiamo di avere un server che accetta connessioni HTTP sulla porta 8080 e connessioni HTTPS sulla porta 8181.

Usiamo iptables per stabilire i seguenti reindirizzamenti:

80  ---> 8080
443 ---> 8181

Supponiamo ora che il nostro server decida di reindirizzare l'utente da una pagina HTTP a una pagina HTTPS. A meno che non riscriviamo attentamente la risposta, verrebbe reindirizzato a https://host:8181/. A questo punto, siamo fregati:

  • Alcuni utenti aggiungerebbero l' https://host:8181/URL ai segnalibri e dovremmo mantenerlo per evitare di rompere i loro segnalibri.
  • Altri utenti non sarebbero in grado di connettersi perché i loro server proxy non supportano porte SSL non standard.

Uso il seguente approccio:

iptables -t mangle -A PREROUTING -p tcp --dport 80 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p tcp --dport 443 -j MARK --set-mark 1
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8181
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -m mark --mark 1 -j ACCEPT
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 8181 -m mark --mark 1 -j ACCEPT

Combinato con la regola REJECT predefinita sulla catena INPUT, questo approccio impedisce agli utenti di connettersi direttamente alle porte 8080, 8181


1
Questo va bene, ma perché non legare il demone a localhost: 8080 invece di 0.0.0.0:8080? Voglio farlo, ma ho bisogno di iptables per quello.
Amala,

Funziona davvero bene.
xtian l'

29

Tradizionalmente su Unix, solo il root può essere associato a porte basse (<1024).

Il modo più semplice per aggirare il problema è eseguire il server su una porta alta (ad esempio 8080) e utilizzare una semplice regola iptables per inoltrare le connessioni dalla porta 80 alla porta 8080. Notare che con questo si perde la protezione aggiuntiva dal porte basse; qualsiasi utente sulla macchina può collegarsi alla porta 8080.


23

Se il tuo sistema lo supporta, potresti utilizzare le funzionalità. Vedi man capabilities, quello che ti serve sarebbe CAP_NET_BIND_SERVICE. No, non li ho mai usati da solo e non so se funzionano davvero :-)


1
funzionano, io uso CAP_NET_RAW per eseguire strumenti come tcpdump come un normale utente.
Justin,

12

Utilizzare un proxy inverso (nginx, apache + mod_proxy) o un proxy inverso nella cache (Squid, Varnish) davanti ai server delle applicazioni!

Con un proxy inverso puoi ottenere molte cose interessanti come:

  • Bilancio del carico
  • Riavvio dei server applicazioni con gli utenti che ricevono una pagina di errore elaborata
  • Accelera le cose con la cache
  • Impostazioni dettagliate che normalmente si eseguono con un proxy inverso e non con un server applicazioni

6

Puoi usare il programma di redir:

sudo redir --lport=80 --laddr=192.168.0.101 --cport 9990 --caddr=127.0.0.1

4

Usa sudo.

Configurare sudo in modo che l'utente normale possa eseguire i comandi appropriati:

/etc/init.d/httpd start

O

apachectl stop

O

/usr/local/apache2/apachectl restart

O

/myapp/myappbin start

(O qualunque altro comando / script che usi per avviare / interrompere un particolare server web / app)


8
Questo ha lo stesso problema: eseguire un servizio come root è una cattiva pratica.
Kevin Panko,

4

la risposta di sunny è corretta, ma potresti riscontrare ulteriori problemi in quanto l'interfaccia di loopback non utilizza la tabella PREROUTING,

quindi le regole di iptables da aggiungere sono due:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8080

3

Con Linux, hai altre due opzioni:

Entrambe le estensioni del kernel Linux consentono di concedere diritti di accesso a un livello molto fine. Ciò consentirebbe di concedere questo processo per aprire la porta 80 ma non erediterà nessuno degli altri diritti di root.

Da quello che ho sentito, grsecurity è molto più semplice da usare ma SELinux è più sicuro.


2

Una soluzione consiste nell'utilizzare iptables per eseguire PAT sui pacchetti per la porta 80. Ad esempio, è possibile utilizzare questo per instradare i pacchetti alla porta locale 8080. Assicurarsi e regolare i pacchetti in uscita sulla porta 80.

In base alla mia esperienza, le funzionalità di autorizzazioni dettagliate di Linux non vengono compilate in kernel standard a causa di problemi di sicurezza.


2

Se si sta tentando di eseguire questa operazione in modo che un comando eseguito dall'utente possa utilizzare la porta 80, le uniche soluzioni sono i trucchi iptables o l'impostazione dell'eseguibile setuid-to-root.

Il modo in cui qualcosa come Apache fa questo (si lega alla porta 80, ma è in esecuzione come qualcuno diverso da root) è quello di eseguire come root, associare alla porta, quindi cambiare la proprietà del processo per l'utente non privilegiato dopo la porta è impostato. Se l'app che stai scrivendo può essere eseguita da root, puoi cambiarne il proprietario con l'utente non privato dopo aver impostato le porte. Ma se questo è solo per un utente medio da eseguire dalla riga di comando, allora dovrai usare una delle altre soluzioni.


2

Quando ho varie applicazioni di servizio Web (script Python, motori Tomcat, ...) che non voglio eseguire come root, di solito configuro un server Web Apache davanti a loro. Apache ascolta la porta 80 e tomcat ascolta 8080.

In apache: s config:

ProxyPass /webapp http://localhost:8080/webapp
ProxyPassReverse /webapp http://localhost:8080/webapp

Consulta la documentazione di mod-proxy per maggiori informazioni: http://httpd.apache.org/docs/2.2/mod/mod_proxy.html


1
Lo svantaggio di questa soluzione è la perdita dell'IP in entrata nei registri Tomcat.
Emmanuel Bourg,

2

Penso che la soluzione migliore sia sgidare la tua app e non appena ha la porta associata dovrebbe perdere i privilegi passando a un altro utente.


1

Alcuni hostystem non consentono di utilizzare il modulo NAT, in questo caso 'iptables' non risolve il problema.

Che ne dici di xinetd?

Nel mio caso (ubuntu 10.04)

# apt-get install xinetd
# touch /etc/xinetd.d/my_redirect
# vim /etc/xinetd.d/my_redirect

Incolla la configurazione:

service my_redirector_80
{
 disable = no
 socket_type = stream
 protocol = tcp
 user = root
 wait = no
 port = 80
 redirect = localhost 8080
 type = UNLISTED
}

Poi:

# service xinetd restart

http://docs.codehaus.org/display/JETTY/port80 spiega meglio.


1
Ciò equivale sostanzialmente a mettere un proxy inverso di fronte al server, ma è piuttosto inefficiente rispetto a soluzioni dedicate come HAproxy, Pound o Varnish che comprendono il protocollo HTTP e possono aggiungere utili intestazioni come X-Forwarded-For.
Emmanuel Bourg,

-1

Per inciso, FreeBSD e Solaris (qualcuno ricorda che uno?) Ti permettono di fare questo (si legano alle basse porte), senza escalation dei privilegi (ad esempio, l'utilizzo di programmi per passare alla radice). Da quando hai specificato Linux, sto solo pubblicando questo come avviso per altri che potrebbero trovare questa domanda.


-1

Necromancing.

Semplice. Con un kernel normale o vecchio, non lo fai.
Come sottolineato da altri, iptables può inoltrare una porta.
Come sottolineato anche da altri, CAP_NET_BIND_SERVICE può anche fare il lavoro.
Ovviamente CAP_NET_BIND_SERVICE fallirà se avvii il tuo programma da uno script, a meno che tu non imposti il ​​cap sull'interprete della shell, il che è inutile, potresti anche eseguire il tuo servizio come root ...
ad esempio per Java, devi applicarlo alla JAVA JVM

sudo /sbin/setcap 'cap_net_bind_service=ep' /usr/lib/jvm/java-8-openjdk/jre/bin/java

Ovviamente, ciò significa che qualsiasi programma Java può associare le porte di sistema.
Dito per mono / .NET.

Sono anche abbastanza sicuro che xinetd non sia la migliore delle idee.
Ma poiché entrambi i metodi sono hack, perché non alzare il limite alzando la restrizione?
Nessuno ha detto che devi eseguire un kernel normale, quindi puoi semplicemente eseguire il tuo.

Devi solo scaricare il sorgente per l'ultimo kernel (o lo stesso che hai attualmente). Successivamente, vai a:

/usr/src/linux-<version_number>/include/net/sock.h:

Lì cerchi questa linea

/* Sockets 0-1023 can't be bound to unless you are superuser */
#define PROT_SOCK       1024

e cambiarlo in

#define PROT_SOCK 0

se non vuoi avere una situazione ssh insicura, la modifichi in questo: #define PROT_SOCK 24

In generale, utilizzerei l'impostazione più bassa di cui hai bisogno, ad esempio 79 per http o 24 quando utilizzo SMTP sulla porta 25.

Questo è già tutto.
Compilare il kernel e installarlo.
Reboot.
Finito: quello stupido limite è ANDATO e funziona anche per gli script.

Ecco come compilare un kernel:

https://help.ubuntu.com/community/Kernel/Compile

# You can get the kernel-source via package linux-source, no manual download required
apt-get install linux-source fakeroot

mkdir ~/src
cd ~/src
tar xjvf /usr/src/linux-source-<version>.tar.bz2
cd linux-source-<version>

# Apply the changes to PROT_SOCK define in /include/net/sock.h

# Copy the kernel config file you are currently using
cp -vi /boot/config-`uname -r` .config

# Install ncurses libary, if you want to run menuconfig
apt-get install libncurses5 libncurses5-dev

# Run menuconfig (optional)
make menuconfig

# Define the number of threads you wanna use when compiling (should be <number CPU cores> - 1), e.g. for quad-core
export CONCURRENCY_LEVEL=3
# Now compile the custom kernel
fakeroot make-kpkg --initrd --append-to-version=custom kernel-image kernel-headers

# And wait a long long time

cd ..

In poche parole, usa iptables se vuoi rimanere sicuro, compila il kernel se vuoi essere sicuro che questa restrizione non ti disturbi mai più.


Qualcuno potrebbe spiegare i voti negativi? Compilazione del kernel non funziona? O è solo perché in seguito non è più possibile eseguire un aggiornamento del kernel dai normali repository?
Quandary

Ho provato questa soluzione ( sudo setcap cap_net_bind_service=+ep /path-to-java/java) ma ottengo sempre java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directoryse java ha i tappi impostati. vedi anche la prima parte di unix.stackexchange.com/a/16670/55508
Daniel Alder

1
Risolto l'errore precedente con l'aggiunta <javahome>/lib/amd64/jli/di ld.so.confe funzionantesudo ldconfig
Daniel Alder
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.