Bir sunucu 80 numaralı bağlantı noktasından Linux'ta normal bir kullanıcı olarak nasıl çalıştırılır?


311

Googled'i bir süredir bir çözüm hakkında buldum, ancak bir cevap bulamadım.

Ubuntu Linux'tayım ve 80 numaralı bağlantı noktasında bir sunucu çalıştırmak istiyorum, ancak Ubuntu'nun güvenlik mekanizması nedeniyle şu hatayı alıyorum:

java.net.BindException: İzin reddedildi: 80

Bu güvenlik mekanizmasını devre dışı bırakmak ya da 80 numaralı bağlantı noktasının tüm kullanıcılar tarafından kullanılabilmesi veya geçerli kullanıcıya 80 numaralı bağlantı noktasına erişmek için gereken ayrıcalıkları atamak için yeterince basit olması gerektiğini düşünüyorum.


3
Sunucuyu ayrıcalıklı olmayan başka bir bağlantı noktasında çalıştırma sorunu nedir? En azından, bu bağlantı noktasında bir sunucuyu çalıştırmak için çok ciddi bir neden belirtmeden güvenlik mekanizmasını devre dışı bırakmak kadar sert bir şey düşünüyoruz. Sunucunun 80 numaralı bağlantı noktasına bağlanması zor kodlanmış mı? Eğer öyleyse, at onu.
Anonim


4
Yapamazsın 1024'ün altındaki bağlantı noktaları ayrıcalıklıdır ve yalnızca kökler üzerindeki dinleme yuvalarını açabilir. Yapılacak uygun şey, açtıktan sonra izinleri bırakmaktır.
Falcon Momot

2
"Anonim" - dünyadaki kullanıcılar, belirli bağlantı noktalarında belirli hizmetleri aramak için eğitildi. Bazı durumlarda, standardize edilmiştir. Örneğin, 80 numaralı bağlantı noktasında HTTP ve 443 numaralı bağlantı noktasında HTTPS. Kullanıcıları ve dünya standartlarını değiştirmek biraz zor.

1
@FalconMomot 1024'ün altındaki bağlantı noktaları ayrıcalıklıysa, Apache sunucusu neden 80 numaralı bağlantı noktasında kök ayrıcalıkları almak için bir parola girmesini gerektirmiyor ve bu şekilde nasıl yapıyorlar? Bence sorgulayıcı bu tür şeyleri nasıl yapacağını bilmek istiyor (teknik olarak root olarak kullanılıyor olsun olmasın). Yanıldığımı söylemekten çekinmeyin, Deepak Mittal.
Shule

Yanıtlar:


355

Kısa cevap: yapamazsın. 1024'ün altındaki portlar sadece root tarafından açılabilir. Yoruma göre - peki, CAP_NET_BIND_SERVICE kullanarak , ancak java binine uygulanan bu yaklaşım, herhangi bir java programını, güvenlik riski olmasa bile istenmeyen bir şekilde, bu ayar ile çalışacak hale getirecektir.

Uzun cevap: 80 numaralı bağlantı noktasını normal kullanıcı olarak açabileceğiniz başka bir bağlantı noktasına yönlendirebilirsiniz.

Kök olarak çalıştır:

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

Geridöngü aygıtları (localhost gibi), önyükleme kurallarını kullanmadığından, localhost vb. Kullanıyorsanız , bu kuralı da ekleyin ( thanks @Francesco ):

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

NOT: Yukarıdaki çözüm çok kullanıcılı sistemler için uygun değildir , çünkü herhangi bir kullanıcı 8080 numaralı bağlantı noktasını (veya kullanmaya karar verdiğiniz diğer herhangi bir yüksek bağlantı noktasını) açabilir, böylece trafiği engelleyebilir. ( CesarB’ye verilen krediler ).

EDIT: yorum sorusuna göre - yukarıdaki kuralı silmek için:

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

Bu gibi bir şey çıkacaktır:

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

İlgilendiğiniz kural nr. 2, silmek için:

# iptables -t nat -D PREROUTING 2

13
@Sunny: Olumsuzluklar batıdaki en hızlı silah için değil, en iyi tepki için. Sizinki şu ana kadarki en iyisidir (sadece iptables'dan bahsettim; aslında tam komut satırını verdiniz). Benimki size ait olan tek şey, diğer kullanıcıların 8080
numaralı

3
Bunun IPv6 ile çalışmadığını unutmayın.
Emmanuel Bourg

3
İstediğim zaman bu kuralı nasıl kaldıracağımı kimse açıklayabilir mi? Çalıştırdıktan sonra, çalışır, ancak göründüğü kadarıyla bir "kural" değil, çünkü ne zaman görünmüyor sudo iptables --list. IPtable'ın ne olduğunu ve ne yaptığını biliyorum, ancak bundan önce hiç kullanmadım.
Enkoder

4
Cevabınız için teşekkürler ... Ubuntu'yu ne zaman yeniden başlatsam, bu kural ortadan kalkar ve tekrar çalıştırmam gerekir. Sonsuza dek kurtarmanın bir yolu var mı?
Coderji

4
@Coderji: topluluk belgelerinde "kaydet" bölümünü kontrol edin: help.ubuntu.com/community/IptablesHowTo
Sunny

79

Authbind kullanın .

Java'nın yalnızca IPv4 yığınını etkinleştirirseniz, Java ile de çalışır. Kullanırım:

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

4
Eğer sunucu Tomcat ise AUTHBIND=yes, / etc / default / tomcat6
Emmanuel Bourg

Varsayılan Java paketi ile Ubuntu sunucusunda çalışamadım ...
Ashley

Ben de, herhangi bir bilinen çözüm?
işaretleyin

10
Bunun authbindolmasına izin vermek için yapılandırmanız gerektiğini unutmayın . Man sayfasından: "/ etc / authbind / byport / port test edildi. Eğer bu dosya arayan kullanıcıya uygulanabiliyorsa, access (2) 'e göre bağlantıya izin verilir." örneğin 80 numaralı bağlantı noktası için sudo touch /etc/authbind/byport/80 ; sudo chmod 777 /etc/authbind/byport/80. İlk kurulumunda authbindgenellikle önceden yapılandırılmış yetkiler yoktur.
Jason C

4
Oh nonononononono, hiçbir zaman 777 hiçbir şey chmod!
Johannes

57

Sisteminiz destekliyorsa, yetenekleri kullanabilirsiniz. İnsan yeteneklerini görün, ihtiyacınız olan CAP_NET_BIND_SERVICE olacaktır.

Daha yeni Debian / Ubuntu'da çalıştırabilirsiniz:

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

bu nodejs için çalışır: setcap 'cap_net_bind_service = + ep' / usr / bin / nodejs
JasonS

5
Bu. Bu cevabın neden daha fazla olumlu olmadığını merak ediyorum. İptables seçeneğinden çok daha kolay imho.
Dominik R

5
bu doğru ve en verimli cevaptır, diğer tüm cevaplar performansa neden olur ya da sadece güvensiz / güvensiz.
OneOfOne

41

Başka bir çözüm de uygulamanızın portuid ile bağlanabilmesi için setuid yapılmasıdır. Kök olarak, aşağıdakileri yapın

chown root ./myapp
chmod +S ./myapp

Bunu yapmanın, kesinlikle doğru yapılmadıkça, potansiyel güvenlik açıklarına maruz kalacağını, çünkü uygulamanızın ağla konuşacağını ve tam root yetkileriyle çalıştığını unutmayın. Bu çözümü kullanırsanız, Apache veya Lighttpd kaynak koduna ya da benzer bir şeye bakmanız gerekir; burada bağlantı noktasını açmak için kök ayrıcalıklarını kullanırlar, ancak hemen bu ayrıcalıkları bırakıp daha düşük ayrıcalıklı bir kullanıcı olurlar. bir hava korsanı tüm bilgisayarı ele geçiremez.

Güncelleme: Bu soruda görüldüğü gibi , 2.6.24'ten beri Linux çekirdeği, " CAP_NET_BIND_SERVICE" özelliğine sahip bir çalıştırılabilir (ancak bir komut dosyasını değil) işaretleyebilmenizi sağlayan yeni bir özelliğe sahip görünüyor . Eğer "libcap2-bin" debian paketini kurarsanız, komutu vererek bunu yapabilirsiniz.

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

6
Uygulama ayrıcalıkları nasıl bırakacağını bilmediği sürece, bu root ile çalışmakla aynı şeydir.
CesarB

14
Bu tehlikeli. Bu, herhangi bir isteğin root olarak çalışacağı anlamına gelir. Apache'nin bile bağlanması için kök olarak başladığı ve sonra ayrıcalıkları başka bir kullanıcıya bıraktığı için.
Güneşli

9
Paul: iptables çok tehlikeli değildir, çünkü uygulama tehlikeye atılsa bile, sistemi saldırılara maruz bırakmaz, en azından root haklarıyla. Uygulamayı root olarak çalıştırmak başka bir hikaye.
Güneşli

1
Herkesin kullanabileceği 8080'e bağlanabildiği ve trafiği engelleyebileceği gibi, Cesar'ların söylediği gibi, iptables için tehlike yalnızca bu çok kullanıcılı bir sistemse ortaya çıkar.
Güneşli

1
lol, kabul edilen cevabın nasıl bir aşk -15
Evan Teran

40

Sadece önünde Nginx kullanıyorum. Localhost'ta da çalışabilir.

  • apt-get install nginx

.. veya ..

  • pkg_add -r nginx

.. ya da işletim sisteminize uygun olanı.

Localhost üzerinde çalışıyorsanız, nginx.conf'da ihtiyacınız olan şey:

sunucu {
        80 dinle;
        server_name some.domain.org;
        yer / {
            proxy_set_header Ana Bilgisayar $ host;
            proxy_set_header X-Gerçek IP $ remote_addr;
            proxy_set_header X Forwarded-For $ proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:8081;
        }
}

Bu çözümü gerçekten beğendim.
thomasfedb

1
Bu, JFrog'un kendilerinden önerilen çözümdür: jfrog.com/confluence/display/RTF/nginx
stolsvik

36

Sunny ve CesarB tarafından önerilen yaklaşım:

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

iyi çalışır ancak küçük bir dezavantajı vardır - kullanıcının 80 yerine 8080 numaralı bağlantı noktasına doğrudan bağlanmasını engellemez.

Bu bir problem olduğunda aşağıdaki senaryoyu inceleyin.

Diyelim ki 8080 numaralı bağlantı noktasındaki HTTP bağlantılarını ve 8181 numaralı bağlantı noktasındaki HTTPS bağlantılarını kabul eden bir sunucumuz var.

Aşağıdaki yönlendirmeleri oluşturmak için iptables kullanıyoruz:

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

Şimdi, sunucumuzun kullanıcıyı bir HTTP sayfasından HTTPS sayfasına yönlendirmeye karar verdiğini varsayalım. Yanıtı dikkatlice yeniden yazmazsak, yönlendirme olacaktır https://host:8181/. Bu noktada, mahvolduk:

  • Bazı kullanıcılar https://host:8181/URL’yi yer imlerine ekler ve yer imlerini kırmamak için bu URL’yi sürdürmemiz gerekir.
  • Proxy sunucuları standart dışı SSL bağlantı noktalarını desteklemediğinden diğer kullanıcılar bağlanamaz.

Aşağıdaki yaklaşımı kullanıyorum:

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

GİRİŞ zincirindeki varsayılan REJECT kuralıyla birleştirildiğinde, bu yaklaşım kullanıcıların doğrudan 8080, 8181 bağlantı noktalarına bağlanmasını önler


1
Bu iyidir, ama neden sadece arka planını yerel ana bilgisayara bağlamak değil: 0.0.0.0:8080 yerine 8080? Bunu yapmak istiyorum, ancak bunun için iptables'a ihtiyacım var.
Amala,

Çalışıyor, gerçekten harika.
xtian

29

Geleneksel olarak Unix'te, sadece root düşük portlara bağlanabilir (<1024).

Bu sorunu çözmenin en basit yolu, sunucunuzu yüksek bir bağlantı noktasında (örneğin, 8080) çalıştırmak ve bağlantı noktalarını bağlantı noktası 80'den bağlantı noktası 8080'e iletmek için basit bir iptables kuralı kullanmaktır. düşük limanlar; makinenizdeki herhangi bir kullanıcı 8080 numaralı bağlantı noktasına bağlanabilir.


23

Sisteminiz destekliyorsa, yetenekleri kullanabilirsiniz. Bak man capabilities, ihtiyacın olan şey olurdu CAP_NET_BIND_SERVICE. Hayır, onları asla kendim kullanmadım ve gerçekten çalışıp çalışmadıklarını bilmiyorum :-)


1
çalışırlar, normal kullanıcı olarak tcpdump gibi araçları çalıştırmak için CAP_NET_RAW kullanırım.
Justin,

12

Uygulama sunucularınızın önünde bir ters vekil (nginx, apache + mod_proxy) veya bir önbellek ters vekil (Kalamar, Vernik) kullanın!

Ters bir proxy ile birçok ilginç şey başarabilirsiniz:

  • Yük dengeleme
  • Uygulama sunucularınızı, süslü bir hata sayfası alan kullanıcılarla yeniden başlatma
  • Önbellek ile işleri hızlandırın
  • Normalde uygulama sunucusuyla değil proxy ile yaptığınız ince ayarlı ayarlar

6

Redir programını kullanabilirsiniz:

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

4

Sudo kullanın.

Sudo'yu normal kullanıcının uygun komutları çalıştırabilmesi için yapılandırın:

/etc/init.d/httpd start

Veya

apachectl stop

Veya

/usr/local/apache2/apachectl restart

Veya

/myapp/myappbin start

(Veya belirli bir web sunucusu / uygulamasını başlatmak / durdurmak için kullandığınız diğer komut / komut dosyaları ne olursa olsun)


8
Bu aynı sorun var - bir hizmeti root olarak çalıştırmak kötü bir uygulamadır.
Kevin Panko

4

sunny'in cevabı doğrudur, ancak geridöngü arabirimi PREROUTING tablosunu kullanmıyorsa ek sorunlar yaşayabilirsiniz.

bu yüzden eklemek için iptables kuralları iki:

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

Linux ile, başka iki seçeneğiniz var:

Her iki Linux çekirdeğindeki uzantılar, çok iyi taneli bir düzeyde erişim hakları verilmesine izin verir. Bu, bu işlemi 80 numaralı bağlantı noktasını açma izni vermenizi sağlar, ancak diğer kök haklarından herhangi birini devralmaz.

Duyduğuma göre grsecurity kullanımı çok daha kolay fakat SELinux daha güvenli.


2

Çözümlerden biri, 80 numaralı bağlantı noktasında paketlerde PAT gerçekleştirmek için iptables kullanmaktır. Örneğin, paketleri yerel bağlantı noktası 8080'e yönlendirmek için kullanabilirsiniz. Giden paketleri tekrar bağlantı noktası 80'e getirdiğinizden emin olun ve ayarlayın.

Tecrübelerime göre, Linux'un ince taneli izinler özellikleri, güvenlik sorunları nedeniyle standart çekirdeğe getirilmemiştir.


2

Bir kullanıcı tarafından çalıştırılan komutun 80 numaralı bağlantı noktasını kullanabilmesi için bunu yapmaya çalışıyorsanız, tek çözümleriniz iptables hileleri veya yürütülebilir setuid-to-root komutunu ayarlamaktır.

Apache gibi bir şey bunu yapar (bu bağlantı noktası 80'e bağlanır, ancak kök dışında bir kişi olarak çalışır), kök olarak çalıştırmak, bağlantı noktasına bağlanır, ardından işlemin sahipliğini bağlantı noktasından sonra ayrıcalıklı olmayan kullanıcı olarak değiştirir ayarlandı. Yazdığınız uygulama root tarafından çalıştırılabiliyorsa , portlar ayarlandıktan sonra sahibini özel olmayan kullanıcıya değiştirmesini sağlayabilirsiniz. Ancak, bu yalnızca ortalama bir kullanıcının komut satırından çalıştırması içinse, diğer çözümlerden birini kullanmanız gerekir.


2

Kök olarak çalıştırmak istemediğim çeşitli web servis uygulamaları (python scriptleri, tomcat motorları, ...) olduğunda, genellikle önlerinde bir apache web sunucusu yapılandırırım. Apache 80 numaralı bağlantı noktasını, tomcat ise 8080 numaralı sürümü dinler.

Apache'de: s config:

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

Daha fazla bilgi için mod-proxy belgelerine bakın: http://httpd.apache.org/docs/2.2/mod/mod_proxy.html


1
Bu çözümün dezavantajı, Tomcat günlüklerinde gelen IP’nin kaybı.
Emmanuel Bourg

2

Bence en iyi çözüm, uygulamanızı sağlamlaştırmak ve limanı bağlı olduğu anda başka bir kullanıcıya geçerek ayrıcalıkları ortadan kaldırması gerekiyor.


1

Bazı ana sistemler NAT modülünü kullanmaya izin vermiyor, 'iptables' bu durumda sorunu çözmüyor.

Peki ya xinetd?

Benim durumumda (ubuntu 10.04)

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

Yapılandırmayı yapıştırın:

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

Sonra:

# service xinetd restart

http://docs.codehaus.org/display/JETTY/port80 daha iyi açıklar.


1
Bu temelde sunucunun önüne ters bir proxy koymakla eşdeğerdir, ancak HTTP protokolünü anlayan ve X-Forwarded-For seviyor gibi faydalı başlıklar ekleyebilen HAproxy, Pound veya Varn gibi özel çözümlerle karşılaştırıldığında verimsizdir.
Emmanuel Bourg

-1

Bir kenara, FreeBSD ve Solaris (herkes hatırlar o biri?) Eğer ayrıcalık iletmeden bu (düşük limanlara bağlama) (yani programları kullanarak root geçmek için) yapalım. Linux'u belirlediğinden beri, bu soruyu bulabilecek başkalarına bunu bir not olarak gönderiyorum.


-1

Necromancing.

Basit. Normal veya eski bir çekirdekli, sen yapmazsın.
Başkaları tarafından belirtildiği gibi iptables bir limanı iletebilir.
Başkalarının da belirttiği gibi, CAP_NET_BIND_SERVICE işi ​​de yapabilir.
Elbette CAP_NET_BIND_SERVICE, programınızı bir betikten başlatırsanız başarısız olur, eğer kabuk tercüman kapağını ayarlamadıysanız, anlamsızdır, hizmetinizi root olarak çalıştırabilirsiniz ...
örneğin Java için uygulamanız gerekir. JAVA JVM'ye

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

Açıkçası, bu daha sonra herhangi bir Java programının sistem bağlantı noktalarını bağlayabileceği anlamına gelir.
Mono / .NET için Dito.

Ayrıca, xinetd'in fikirlerin en iyisi olmadığından eminim.
Ancak her iki yöntem de kesmek olduğundan, neden sadece kısıtlamayı kaldırarak limiti kaldırmıyorsunuz?
Kimse normal bir çekirdek çalıştırman gerektiğini söylemedi, o yüzden kendi işini kendin yapabiliyorsun.

En son çekirdeğin kaynağını (veya şu anda sahip olduğunuzla aynı) indirebilirsiniz. Daha sonra:

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

Orada bu çizgiyi arıyorsun

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

ve değiştirin

#define PROT_SOCK 0

Eğer güvensiz bir ssh durumuna sahip olmak istemezseniz, bunu şöyle değiştirirsiniz: #define PROT_SOCK 24

Genellikle, ihtiyacınız olan en düşük ayarı kullanırdım, örneğin http için 79 veya 25 numaralı bağlantı noktasında SMTP kullanırken.

Zaten hepsi bu.
Çekirdeği derleyin ve kurun.
Yeniden Başlatma.
Bitti - bu aptal limit GONE ve aynı zamanda scriptler için de geçerli.

İşte bir çekirdeği nasıl derlediğin:

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

Kısacası, güvenli kalmak istiyorsanız iptables kullanın, bu kısıtlamanın sizi bir daha asla rahatsız etmeyeceğinden emin olmak istiyorsanız çekirdeği derleyin.


Birisi, lütfen aşağı yönleri açıklar mı? Çekirdek derleme çalışmıyor mu? Yoksa bunun nedeni daha sonra normal depolardan bir çekirdek yükseltme yapamamanız mı?
Quandary

Bu çözümü denedim ( sudo setcap cap_net_bind_service=+ep /path-to-java/java), ancak java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directoryjava büyük harf ayarladıysa her zaman alırım . ayrıca bkz. unix.stackexchange.com/a/16670/55508
Daniel Alder

1
Ekleyerek önceki hatayı çözüldü <javahome>/lib/amd64/jli/için ld.so.confve koşusudo ldconfig
Daniel Alder
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.