Jak uruchomić serwer na porcie 80 jako normalny użytkownik w systemie Linux?

311

Długo szukałem rozwiązania w Google, ale nie mogłem znaleźć odpowiedzi.

Jestem na Ubuntu Linux i chcę uruchomić serwer na porcie 80, ale z powodu mechanizmu bezpieczeństwa Ubuntu pojawia się następujący błąd:

java.net.BindException: Odmowa dostępu: 80

Myślę, że powinno być wystarczająco proste, aby albo wyłączyć ten mechanizm bezpieczeństwa, aby port 80 był dostępny dla wszystkich użytkowników, albo przypisać wymagane uprawnienia bieżącemu użytkownikowi, aby uzyskać dostęp do portu 80.

Deepak Mittal
źródło
3
Na czym polega problem z uruchomieniem serwera na innym nieuprzywilejowanym porcie? Zastanawiasz się nad czymś tak surowym, jak wyłączenie mechanizmu bezpieczeństwa bez podania co najmniej bardzo poważnego powodu do uruchomienia serwera na tym porcie. Czy serwer jest na stałe przypisany do portu 80? Jeśli tak, wyrzuć to.
Anonimowy
4
Nie możesz Porty poniżej 1024 są uprzywilejowane i tylko root może otwierać na nich gniazda nasłuchujące. Właściwą czynnością jest usunięcie uprawnień po ich otwarciu.
Falcon Momot,
2
„Anonimowy” - użytkownicy na całym świecie zostali przeszkoleni w zakresie wyszukiwania niektórych usług w określonych portach. W niektórych przypadkach został ustandaryzowany. Na przykład HTTP na porcie 80 i HTTPS na porcie 443. Trudno jest zmienić użytkowników i standardy na świecie.
1
@FalconMomot Jeśli porty poniżej 1024 są uprzywilejowane, to dlaczego serwer Apache nie wymaga wpisania hasła, aby uzyskać uprawnienia roota na porcie 80, i jak to zrobić? Myślę, że pytający chce wiedzieć, jak to zrobić (czy jest to technicznie używane jako root, czy nie). Powiedz mi, czy się mylę, Deepak Mittal.
Shule

Odpowiedzi:

355

Krótka odpowiedź: nie możesz. Porty poniżej 1024 można otwierać tylko przez rootowanie. Zgodnie z komentarzem - cóż, możesz, używając CAP_NET_BIND_SERVICE , ale takie podejście zastosowane do bin Java spowoduje, że każdy program Java będzie działał z tym ustawieniem, co jest niepożądane, jeśli nie stanowi zagrożenia bezpieczeństwa.

Długa odpowiedź: możesz przekierowywać połączenia na porcie 80 na inny port, który możesz otworzyć jako zwykły użytkownik.

Uruchom jako root:

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

Ponieważ urządzenia sprzężenia zwrotnego (takie jak localhost) nie używają reguł przekierowania, jeśli musisz użyć localhost itp., Dodaj również tę regułę ( dzięki @Francesco ):

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

UWAGA: Powyższe rozwiązanie nie jest odpowiednie dla systemów z wieloma użytkownikami, ponieważ każdy użytkownik może otworzyć port 8080 (lub inny wysoki port, z którego zdecydujesz się skorzystać), w ten sposób przechwytując ruch. (Kuponów do CesarB ).

EDYCJA: jak na pytanie w komentarzu - aby usunąć powyższą zasadę:

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

Spowoduje to wyświetlenie czegoś takiego:

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

Reguła, którą jesteś zainteresowany, to nr. 2, aby go usunąć:

# iptables -t nat -D PREROUTING 2
Słoneczny
źródło
13
@Sunny: głosy poparcia nie dotyczą najszybszej broni na zachodzie, ale najlepszych odpowiedzi. Twój jest jak dotąd najlepszy (wspomniałem tylko o iptables; faktycznie podałeś pełną linię poleceń). Jedyną rzeczą, jakiej nie ma moja, jest zastrzeżenie, że inni użytkownicy mogą również łączyć się z portem 8080.
CesarB
3
Pamiętaj, że to nie działa z IPv6.
Emmanuel Bourg
3
Czy ktoś mógłby wyjaśnić, jak mogę później usunąć tę regułę, kiedy chcę? Po uruchomieniu działa, ale najwyraźniej nie jest to „reguła”, ponieważ nie pojawia się, kiedy to robię sudo iptables --list. Wiem, czym jest iptables, ale nigdy tak naprawdę nie korzystałem z tego wcześniej.
Koder
4
Dzięki za odpowiedź ... przy każdym ponownym uruchomieniu Ubuntu ta reguła znika i muszę ją ponownie uruchomić. Czy istnieje sposób, aby zapisać go na zawsze?
Coderji
4
@Coderji: sprawdź sekcję „zapisz” w dokumentacji społeczności: help.ubuntu.com/community/IptablesHowTo
Sunny,
79

Użyj authbind .

Działa nawet z Javą, jeśli włączysz stos Java tylko IPv4. Używam:

authbind --deep $JAVA_HOME/bin/java -Djava.net.preferIPv4Stack=true …
geocar
źródło
4
Jeśli serwerem jest Tomcat, możesz automatycznie korzystać z automatycznego uwierzytelniania, ustawiając AUTHBIND=yesw / etc / default / tomcat6
Emmanuel Bourg
Nie mogłem tego uruchomić na serwerze Ubuntu z domyślnym pakietem Java ...
Ashley
Ja też, jakieś znane rozwiązanie?
zaznacz
10
Pamiętaj, że musisz tak skonfigurować, authbindaby tak się stało. Ze strony podręcznika: „/ etc / authbind / byport / port jest testowany. Jeśli ten plik jest dostępny do wykonania dla wywołującego użytkownika, zgodnie z access (2), wówczas autoryzacja jest powiązana z portem”. Np na porcie 80 sudo touch /etc/authbind/byport/80 ; sudo chmod 777 /etc/authbind/byport/80. Początkowa instalacja authbindzazwyczaj nie ma żadnych wstępnie skonfigurowanych autoryzacji.
Jason C
4
O, nonononononono, nigdy nie chmod 777 niczego!
Johannes
57

Jeśli twój system to obsługuje, możesz użyć funkcji. Zobacz możliwości człowieka, potrzebna będzie CAP_NET_BIND_SERVICE.

W nowszych systemach Debian / Ubuntu możesz uruchomić:

sudo apt-get install libcap2-bin 
sudo setcap 'cap_net_bind_service=+ep' /path/to/program
Otto Kekäläinen
źródło
działa to dla nodejs: setcap 'cap_net_bind_service = + ep' / usr / bin / nodejs
JasonS
5
To. Zastanawiam się, dlaczego ta odpowiedź nie ma więcej pozytywnych opinii. O wiele łatwiej niż imho opcja iptables.
Dominik R
5
jest to poprawna i najbardziej wydajna odpowiedź, wszystkie pozostałe odpowiedzi powodują pogorszenie wydajności lub po prostu niepewne / niepewne.
OneOfOne
41

Innym rozwiązaniem jest skonfigurowanie aplikacji jako „setuid”, aby mogła się łączyć z portem 80. Jako root wykonaj następujące czynności

chown root ./myapp
chmod +S ./myapp

Pamiętaj, że jeśli to zrobisz, chyba że zrobisz to całkowicie poprawnie, narazisz Cię na potencjalne dziury w zabezpieczeniach, ponieważ Twoja aplikacja będzie rozmawiać z siecią i będzie działać z pełnymi uprawnieniami roota. Jeśli skorzystasz z tego rozwiązania, powinieneś spojrzeć na kod źródłowy Apache lub Lighttpd lub coś podobnego, gdzie używają uprawnień roota do otwarcia portu, ale natychmiast porzuć te uprawnienia i „zostań” uprzywilejowanym użytkownikiem, aby porywacz nie może przejąć całego komputera.

Aktualizacja: Jak widać w tym pytaniu , wydaje się, że jądra Linuksa od wersji 2.6.24 mają nową możliwość, która pozwala oznaczyć plik wykonywalny (ale oczywiście nie skrypt) jako posiadający funkcję „ CAP_NET_BIND_SERVICE”. Jeśli zainstalujesz pakiet debian „libcap2-bin”, możesz to zrobić, wydając polecenie

setcap 'cap_net_bind_service=+ep' /path/to/program
Paul Tomblin
źródło
6
To jest to samo, co uruchamianie jako root, chyba że aplikacja wie, jak usunąć uprawnienia.
CesarB,
14
To jest niebezpieczne. Oznacza to, że każde żądanie będzie działać jako root. To z tego powodu, że nawet apache zaczyna się jako root do powiązania, a następnie upuszcza uprawnienia na innego użytkownika.
Sunny,
9
Paul: iptables nie jest tak niebezpieczne, ponieważ nawet jeśli aplikacja zostanie przejęta, nie narazi systemu na ataki, przynajmniej nie z uprawnieniami roota. Uruchamianie aplikacji jako root to inna historia.
Sunny,
1
Niebezpieczeństwo dla iptables jest tylko wtedy, gdy jest to system dla wielu użytkowników, jak powiedział CesarB, ponieważ każdy może połączyć się z 8080 i przechwycić ruch.
Sunny
1
lol, uwielbiam, jak przyjęta odpowiedź ma -15
Evan Teran
40

Po prostu używam Nginx z przodu. Może działać również na localhost.

  • apt-get install nginx

.. lub ..

  • pkg_add -r nginx

.. lub co kiedykolwiek pasuje do twojego systemu operacyjnego.

Wszystko, czego potrzebujesz w nginx.conf, jeśli działa na localhost, to:

serwer {
        słuchaj 80;
        nazwa_serwera some.domain.org;
        Lokalizacja / {
            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;
        }
}
CosmicB
źródło
Naprawdę podoba mi się to rozwiązanie.
thomasfedb
1
To jest (jedno z) sugerowanych rozwiązań samego JFrog
stolsvik
36

Podejście zaproponowane przez Sunny i CesarB:

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

działa dobrze, ale ma niewielką wadę - nie uniemożliwia użytkownikowi bezpośredniego połączenia z portem 8080 zamiast 80.

Rozważ następujący scenariusz, gdy może to stanowić problem.

Załóżmy, że mamy serwer, który akceptuje połączenia HTTP na porcie 8080 i połączenia HTTPS na porcie 8181.

Używamy iptables do ustanowienia następujących przekierowań:

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

Załóżmy teraz, że nasz serwer zdecyduje o przekierowaniu użytkownika ze strony HTTP na stronę HTTPS. O ile nie zmienimy dokładnie odpowiedzi, przekieruje na nią https://host:8181/. W tym momencie jesteśmy przykręceni:

  • Niektórzy użytkownicy dodaliby zakładki do https://host:8181/adresu URL i musielibyśmy utrzymywać ten adres URL, aby uniknąć zerwania zakładek.
  • Inni użytkownicy nie będą mogli się połączyć, ponieważ ich serwery proxy nie obsługują niestandardowych portów SSL.

Stosuję następujące podejście:

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

W połączeniu z domyślną regułą ODRZUCENIA w łańcuchu WEJŚCIA ta metoda uniemożliwia użytkownikom bezpośrednie połączenie z portami 8080, 8181

Misza
źródło
1
To dobrze, ale dlaczego nie po prostu powiązać demona z localhost: 8080 zamiast 0.0.0.0:8080? Chcę to zrobić, ale do tego potrzebuję iptables.
Amala,
Działa, naprawdę fajnie.
xtian
29

Tradycyjnie w Uniksie tylko root może się łączyć z niskimi portami (<1024).

Najprostszym sposobem obejścia tego problemu jest uruchomienie serwera na wysokim porcie (na przykład 8080) i użycie prostej reguły iptables do przekazywania połączeń z portu 80 na port 8080. Zauważ, że dzięki temu tracisz dodatkową ochronę przed niskie porty; każdy użytkownik na twoim komputerze może połączyć się z portem 8080.

CesarB
źródło
23

Jeśli twój system to obsługuje, możesz użyć funkcji. Widzisz man capabilities, potrzebowałbyś tego CAP_NET_BIND_SERVICE. Nie, nigdy ich nie używałem i nie wiem, czy naprawdę działają :-)

WMR
źródło
1
działają, używam CAP_NET_RAW do uruchamiania narzędzi takich jak tcpdump jako zwykły użytkownik.
Justin
12

Użyj odwrotnego proxy (nginx, apache + mod_proxy) lub buforującego odwrotnego proxy (Squid, Varnish) przed serwerami aplikacji!

Dzięki zwrotnemu proxy możesz osiągnąć wiele interesujących rzeczy, takich jak:

  • Równoważenie obciążenia
  • Ponowne uruchamianie serwerów aplikacji, gdy użytkownicy otrzymują fantazyjną stronę błędu
  • Przyspiesz działanie dzięki pamięci podręcznej
  • Szczegółowe ustawienia, które zwykle wykonuje się z odwrotnym proxy, a nie z serwerem aplikacji
Giovanni Toraldo
źródło
6

Możesz użyć programu redir:

sudo redir --lport=80 --laddr=192.168.0.101 --cport 9990 --caddr=127.0.0.1
użytkownik340994
źródło
4

Użyj sudo.

Skonfiguruj sudo, aby zwykły użytkownik mógł uruchamiać odpowiednie polecenia:

/etc/init.d/httpd start

Lub

apachectl stop

Lub

/usr/local/apache2/apachectl restart

Lub

/myapp/myappbin start

(Lub cokolwiek innego polecenia / skryptu, którego używasz do uruchamiania / zatrzymywania określonego serwera / aplikacji)

Nie teraz
źródło
8
Ma to ten sam problem - uruchamianie usługi jako root to zła praktyka.
Kevin Panko
4

odpowiedź słoneczna jest poprawna, ale możesz napotkać dodatkowe problemy, ponieważ interfejs pętli zwrotnej nie korzysta z tabeli PREROUTING,

więc reguły iptables do dodania są dwa:

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
Francesco
źródło
3

W Linuksie masz dwie inne opcje:

Oba rozszerzenia jądra systemu Linux umożliwiają przyznanie praw dostępu na bardzo drobnym poziomie szczegółowości. Umożliwiłoby to przyznanie temu procesowi otwarcia portu 80, ale nie odziedziczyłby żadnych innych praw root.

Z tego, co słyszałem, grsecurity jest znacznie prostszy w użyciu, ale SELinux jest bezpieczniejszy.

Aaron Digulla
źródło
2

Jednym z rozwiązań jest użycie iptables do wykonania PAT na pakietach dla portu 80. Możesz to wykorzystać do przekierowania pakietów na przykład do lokalnego portu 8080. Upewnij się i dostosuj wychodzące pakiety z powrotem do portu 80.

Z mojego doświadczenia wynika, że ​​funkcje drobnoziarnistych uprawnień systemu Linux nie są kompilowane do standardowych jąder ze względu na problemy z bezpieczeństwem.


źródło
2

Jeśli próbujesz to zrobić, aby polecenie uruchomione przez użytkownika mogło korzystać z portu 80, wówczas jedynymi rozwiązaniami są sztuczki iptables lub ustawienie wykonywalnego setuid-root-root.

Sposób, w jaki robi to Apache (łączy się z portem 80, ale działa jako ktoś inny niż root), polega na uruchomieniu jako root, powiązaniu z portem, a następnie zmianie własności procesu na nieuprzywilejowanego użytkownika po porcie jest skonfigurowany. Jeśli pisana aplikacja może być uruchamiana przez użytkownika root, możesz ją zmienić na właściciela innego niż prywatny po skonfigurowaniu portów. Ale jeśli jest to tylko dla przeciętnego użytkownika do uruchomienia z wiersza poleceń, musisz użyć jednego z innych rozwiązań.

rjray
źródło
2

Kiedy mam różne aplikacje do obsługi stron internetowych (skrypty python, silniki tomcat, ...), których nie chcę uruchamiać jako root, zwykle konfiguruję przed nimi serwer WWW Apache. Apache nasłuchuje na porcie 80, a tomcat nasłuchuje na 8080.

W konfiguracji apache: s:

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

Aby uzyskać więcej informacji, zobacz dokumentację mod-proxy: http://httpd.apache.org/docs/2.2/mod/mod_proxy.html


źródło
1
Wadą tego rozwiązania jest utrata przychodzącego adresu IP w dziennikach Tomcat.
Emmanuel Bourg,
2

Myślę, że najlepszym rozwiązaniem jest sgid twojej aplikacji i jak tylko zostanie ona powiązana z portem, powinna zrezygnować z uprawnień, przełączając się na innego użytkownika.

Anxy Dicy
źródło
1

Niektóre systemy hostów nie pozwalają na korzystanie z modułu NAT, w tym przypadku „iptables” nie rozwiązuje problemu.

Co powiesz na Xinetd?

W moim przypadku (ubuntu 10.04)

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

Wklej konfigurację:

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

Następnie:

# service xinetd restart

http://docs.codehaus.org/display/JETTY/port80 wyjaśnia lepiej.

Tomasz
źródło
1
Jest to zasadniczo równoważne z umieszczeniem odwrotnego proxy przed serwerem, ale jest raczej nieefektywne w porównaniu do dedykowanych rozwiązań, takich jak HAproxy, Pound lub Varnish, które rozumieją protokół HTTP i mogą dodawać przydatne nagłówki, takie jak X-Forwarded-For.
Emmanuel Bourg,
-1

Tak na marginesie, FreeBSD i Solaris (ktoś pamięta , że jeden?) Pozwalają zrobić to (wiążą się z niskimi portów) bez przekroczenia uprawnień (czyli przy użyciu programów, aby przejść do katalogu głównego). Ponieważ podałeś Linuksa, zamieszczam to jako powiadomienie dla innych osób, które mogą znaleźć to pytanie.

Daniel C. Sobral
źródło
-1

Nekromancja.

Prosty. Z normalnym lub starym jądrem nie.
Jak zauważyli inni, iptables może przekierować port.
Jak zauważyli także inni, CAP_NET_BIND_SERVICE może również wykonać zadanie.
Oczywiście CAP_NET_BIND_SERVICE nie powiedzie się, jeśli uruchomisz program ze skryptu, chyba że ustawisz ograniczenie interpretera powłoki, co jest bezcelowe, możesz równie dobrze uruchomić swoją usługę jak root ...
np. W przypadku Java, musisz ją zastosować do JVVA JVM

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

Oczywiście oznacza to, że każdy program Java może powiązać porty systemowe.
Dito dla mono / .NET.

Jestem też całkiem pewien, że xinetd nie jest najlepszym pomysłem.
Ale skoro obie metody to hacki, dlaczego nie po prostu podnieść limit przez zniesienie ograniczenia?
Nikt nie powiedział, że musisz uruchomić normalne jądro, więc możesz po prostu uruchomić własne.

Po prostu pobierasz źródło najnowszego jądra (lub tego samego, co aktualnie posiadasz). Następnie przejdziesz do:

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

Tam szukasz tej linii

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

i zmień na

#define PROT_SOCK 0

jeśli nie chcesz mieć niepewnej sytuacji ssh, zmień to na: # zdefiniuj PROT_SOCK 24

Zasadniczo użyłbym najniższego potrzebnego ustawienia, np. 79 dla http lub 24, gdy używasz SMTP na porcie 25.

To już wszystko.
Skompiluj jądro i zainstaluj je.
Restart.
Zakończone - ten głupi limit Zniknął, i działa również w przypadku skryptów.

Oto jak skompilujesz jądro:

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 ..

W skrócie, użyj iptables, jeśli chcesz zachować bezpieczeństwo, skompiluj jądro, jeśli chcesz mieć pewność, że to ograniczenie nigdy więcej nie będzie Ci przeszkadzać.

Kłopot
źródło
Czy ktoś mógłby wyjaśnić opinie negatywne? Kompilacja jądra nie działa? A może to dlatego, że później nie możesz już wykonać aktualizacji jądra z normalnych repozytoriów?
Quandary
Próbowałem tego rozwiązania ( sudo setcap cap_net_bind_service=+ep /path-to-java/java), ale zawsze otrzymuję, java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directoryjeśli Java ma ustawione ograniczenia. zobacz także pierwszą część unix.stackexchange.com/a/16670/55508
Daniel Alder
1
Rozwiązał poprzedni błąd dodając <javahome>/lib/amd64/jli/do ld.so.confi bieganiesudo ldconfig
Daniel Alder