Bagaimana menjalankan server pada port 80 sebagai pengguna normal di Linux?

311

Saya telah mencari Google tentang solusi untuk beberapa waktu, tetapi tidak dapat menemukan jawaban.

Saya di Ubuntu Linux dan ingin menjalankan server pada port 80, tetapi karena mekanisme keamanan Ubuntu, saya mendapatkan kesalahan berikut:

java.net.BindException: Izin ditolak: 80

Saya pikir itu harus cukup sederhana untuk menonaktifkan mekanisme keamanan ini sehingga port 80 tersedia untuk semua pengguna atau untuk menetapkan hak yang diperlukan untuk pengguna saat ini untuk mengakses port 80.

Deepak Mittal
sumber
3
Apa masalah untuk menjalankan server di port lain yang tidak terjangkau? Anda berpikir tentang sesuatu yang sekeras menonaktifkan mekanisme keamanan tanpa memberikan setidaknya alasan yang sangat serius untuk menjalankan server di port itu. Apakah server hardcoded untuk mengikat ke port 80? Jika demikian, buang saja.
Anonim
5
kemungkinan duplikat dari pengguna Biasa menggunakan porta di bawah 1024
Roman
4
Kamu tidak bisa Port di bawah 1024 adalah hak istimewa dan hanya root yang bisa membuka soket pendengarannya. Hal yang tepat untuk dilakukan adalah menjatuhkan izin setelah membukanya.
Falcon Momot
2
"Anonim" - pengguna di dunia telah dilatih untuk mencari layanan tertentu di pelabuhan tertentu. Dalam beberapa kasus, ini telah distandarisasi. Misalnya, HTTP pada port 80 dan HTTPS pada port 443. Agak sulit untuk mengubah pengguna dan standar dunia.
1
@ FalconMomot Jika port di bawah 1024 adalah hak istimewa, mengapa server Apache tidak memerlukan satu untuk memasukkan kata sandi untuk mendapatkan hak akses root pada port 80, dan bagaimana mereka melakukannya dengan cara itu? Saya pikir si penanya ingin tahu bagaimana melakukan hal-hal seperti itu (apakah secara teknis digunakan sebagai root atau tidak). Jangan ragu untuk memberi tahu saya jika saya salah, Deepak Mittal.
Shule

Jawaban:

355

Jawaban singkat: Anda tidak bisa. Port di bawah 1024 hanya bisa dibuka oleh root. Sesuai komentar - well, Anda bisa, menggunakan CAP_NET_BIND_SERVICE , tetapi pendekatan itu, yang diterapkan ke java bin akan membuat program java apa pun untuk dijalankan dengan pengaturan ini, yang tidak diinginkan, jika bukan risiko keamanan.

Jawaban panjangnya: Anda dapat mengalihkan koneksi pada port 80 ke beberapa port lain yang dapat Anda buka sebagai pengguna normal.

Jalankan sebagai root:

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

Karena perangkat loopback (seperti localhost) tidak menggunakan aturan prerouting, jika Anda perlu menggunakan localhost, dll., Tambahkan aturan ini juga ( terima kasih @Francesco ):

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

CATATAN: Solusi di atas tidak cocok untuk sistem multi-pengguna, karena setiap pengguna dapat membuka port 8080 (atau port tinggi lainnya yang Anda putuskan untuk digunakan), sehingga mengganggu lalu lintas. (Kredit untuk CesarB ).

EDIT: sesuai pertanyaan komentar - untuk menghapus aturan di atas:

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

Ini akan menampilkan sesuatu seperti:

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

Aturan yang Anda minati adalah nr. 2, jadi untuk menghapusnya:

# iptables -t nat -D PREROUTING 2
Cerah
sumber
13
@Sunny: upvotes bukan untuk senjata tercepat di barat, tetapi untuk respon terbaik. Hormat saya adalah yang terbaik sejauh ini (saya hanya menyebutkan iptables; Anda benar-benar memberikan baris perintah penuh). Satu-satunya hal yang saya miliki bukan milik Anda adalah peringatan tentang pengguna lain yang juga dapat mengikat ke port 8080.
CesarB
3
Perhatikan bahwa ini tidak berfungsi dengan IPv6.
Emmanuel Bourg
3
Adakah yang bisa menjelaskan bagaimana saya bisa menghapus aturan ini nanti ketika saya mau? Setelah menjalankannya, ia berfungsi, tetapi ternyata itu bukan "aturan" karena tidak muncul ketika saya melakukannya sudo iptables --list. Saya tahu apa itu iptables dan apa yang saya lakukan, tetapi saya belum pernah menggunakannya sebelumnya.
Encoderer
4
Terima kasih atas jawaban Anda ... setiap kali saya reboot Ubuntu, aturan ini menghilang dan saya harus menjalankannya lagi. Apakah ada cara untuk menyelamatkannya selamanya?
Coderji
4
@Coderji: periksa bagian "simpan" di dokumentasi komunitas: help.ubuntu.com/community/IptablesHowTo
Sunny
79

Gunakan authbind .

Ia bahkan bekerja dengan Java jika Anda mengaktifkan stack Java-IPv4 saja. Saya menggunakan:

authbind --deep $JAVA_HOME/bin/java -Djava.net.preferIPv4Stack=true …
geocar
sumber
4
Jika servernya adalah Tomcat, Anda dapat menggunakan authbind secara otomatis dengan mengatur AUTHBIND=yesdi / etc / default / tomcat6
Emmanuel Bourg
Saya tidak bisa menjalankannya di server Ubuntu dengan paket Java default ...
Ashley
Saya juga, ada solusi yang dikenal?
tandai
10
Perhatikan bahwa Anda harus mengonfigurasi authbinduntuk benar-benar membiarkan ini terjadi. Dari halaman manual: "/ etc / authbind / byport / port diuji. Jika file ini dapat diakses untuk dieksekusi ke pengguna panggilan, sesuai dengan akses (2), maka mengikat ke port itu sah." , misalnya untuk port 80 sudo touch /etc/authbind/byport/80 ; sudo chmod 777 /etc/authbind/byport/80,. Pemasangan awal authbindumumnya tidak memiliki otorisasi pra-konfigurasi.
Jason C
4
Oh nonononononono, jangan pernah chmod 777 apa pun!
Johannes
57

Jika sistem Anda mendukungnya, Anda mungkin dapat menggunakan kapabilitas. Lihat kapabilitas man, yang Anda butuhkan adalah CAP_NET_BIND_SERVICE.

Pada Debian / Ubuntu yang lebih baru Anda dapat menjalankan:

sudo apt-get install libcap2-bin 
sudo setcap 'cap_net_bind_service=+ep' /path/to/program
Otto Kekäläinen
sumber
ini berfungsi untuk nodejs: setcap 'cap_net_bind_service = + ep' / usr / bin / nodejs
JasonS
5
Ini. Saya bertanya-tanya mengapa jawaban ini tidak memiliki lebih banyak suara. Jauh lebih mudah daripada opsi iptables imho.
Dominik R
5
ini adalah jawaban yang benar dan paling efisien, semua jawaban yang lain menyebabkan kinerja yang baik atau hanya rapuh / tidak aman.
OneOfOne
41

Solusi lain adalah membuat setuid aplikasi Anda sehingga dapat mengikat dengan port 80. Sebagai root, lakukan hal berikut

chown root ./myapp
chmod +S ./myapp

Ingatlah bahwa melakukan hal ini, kecuali jika dilakukan dengan benar, akan membuat Anda menghadapi celah keamanan potensial, karena aplikasi Anda akan berbicara dengan jaringan, dan akan berjalan dengan hak root penuh. Jika Anda mengambil solusi ini, Anda harus melihat kode sumber untuk Apache atau Lighttpd atau yang serupa, di mana mereka menggunakan hak akses root untuk membuka port, tetapi kemudian segera menyerahkan privs itu dan "menjadi" pengguna dengan hak istimewa lebih rendah sehingga pembajak tidak dapat mengambil alih seluruh komputer Anda.

Pembaruan: Seperti yang terlihat dalam pertanyaan ini , tampaknya kernel Linux sejak 2.6.24 memiliki kemampuan baru yang memungkinkan Anda untuk menandai sebuah executable (tapi bukan skrip, tentu saja) sebagai memiliki CAP_NET_BIND_SERVICEkapabilitas " ". Jika Anda menginstal paket debian "libcap2-bin", Anda dapat melakukannya dengan mengeluarkan perintah

setcap 'cap_net_bind_service=+ep' /path/to/program
Paul Tomblin
sumber
6
Itu sama dengan menjalankan sebagai root, kecuali jika aplikasi tahu cara menghapus hak istimewa.
CesarB
14
Ini berbahaya. Ini berarti bahwa setiap permintaan akan berjalan sebagai root. Itu karena alasan bahwa bahkan apache dimulai sebagai root untuk mengikat, dan kemudian menjatuhkan hak istimewa kepada pengguna lain.
Cerah
9
Paul: iptables tidak begitu berbahaya, karena meskipun aplikasi dikompromikan, itu tidak akan mengekspos sistem pada serangan, setidaknya tidak dengan hak akses root. Menjalankan aplikasi sebagai root adalah cerita lain.
Cerah
1
Bahaya untuk iptables hanya jika ini adalah sistem multi-pengguna, seperti kata CesarB, karena siapa pun dapat mengikat ke 8080, dan mencegat lalu lintas.
Cerah
1
lol, suka bagaimana jawaban yang diterima memiliki -15
Evan Teran
40

Saya cukup menggunakan Nginx di depan. Itu dapat berjalan di localhost juga.

  • apt-get install nginx

.. atau ..

  • pkg_add -r nginx

.. atau apa pun yang sesuai dengan OS Anda.

Yang Anda butuhkan di nginx.conf, jika dijalankan di localhost, adalah:

server {
        dengarkan 80;
        server_name some.domain.org;
        lokasi / {
            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
sumber
Saya sangat suka solusi ini.
thomasfedb
1
Ini adalah (salah satu) solusi yang disarankan dari JFrog sendiri: jfrog.com/confluence/display/RTF/nginx
stolsvik
36

Pendekatan yang diajukan oleh Sunny dan CesarB:

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

berfungsi dengan baik tetapi memiliki kelemahan kecil - itu tidak mencegah pengguna untuk terhubung langsung ke port 8080, bukan 80.

Pertimbangkan skenario berikut ketika ini bisa menjadi masalah.

Katakanlah kita memiliki server yang menerima koneksi HTTP pada port 8080 dan koneksi HTTPS pada port 8181.

Kami menggunakan iptables untuk menetapkan pengalihan berikut:

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

Sekarang, misalkan server kami memutuskan untuk mengalihkan pengguna dari halaman HTTP ke halaman HTTPS. Kecuali jika kita dengan hati-hati menulis ulang responsnya, itu akan dialihkan ke https://host:8181/. Pada titik ini, kita kacau:

  • Beberapa pengguna akan menandai https://host:8181/URL dan kami perlu mempertahankan URL ini untuk menghindari melanggar bookmark mereka.
  • Pengguna lain tidak akan dapat terhubung karena server proxy mereka tidak mendukung port SSL non-standar.

Saya menggunakan pendekatan berikut:

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

Digabungkan dengan aturan REJECT default pada rantai INPUT, pendekatan ini mencegah pengguna untuk terhubung langsung ke port 8080, 8181

Misha
sumber
1
Ini bagus, tetapi mengapa tidak hanya mengikat daemon ke localhost: 8080 bukannya 0.0.0.0:8080? Saya ingin melakukan itu, tetapi saya perlu iptables untuk itu.
Amala
Ini bekerja, sangat keren.
xtian
29

Secara tradisional pada Unix, hanya root yang dapat mengikat port rendah (<1024).

Cara paling sederhana untuk mengatasi ini adalah dengan menjalankan server Anda pada port tinggi (misalnya, 8080) dan menggunakan aturan iptables sederhana untuk meneruskan koneksi dari port 80 ke port 8080. Perhatikan bahwa dengan ini Anda kehilangan perlindungan ekstra dari port rendah; setiap pengguna di komputer Anda dapat mengikat ke port 8080.

CesarB
sumber
23

Jika sistem Anda mendukungnya, Anda mungkin dapat menggunakan kapabilitas. Lihat man capabilities, yang Anda butuhkan adalah CAP_NET_BIND_SERVICE. Tidak, saya belum pernah menggunakannya sendiri dan saya tidak tahu apakah mereka benar-benar berfungsi :-)

WMR
sumber
1
mereka berfungsi, saya menggunakan CAP_NET_RAW untuk menjalankan alat seperti tcpdump sebagai pengguna normal.
Justin
12

Gunakan proxy terbalik (nginx, apache + mod_proxy) atau proxy reverse caching (Squid, Varnish) di depan server aplikasi Anda!

Dengan proxy terbalik Anda dapat mencapai banyak hal menarik seperti:

  • Penyeimbang beban
  • Mulai ulang server aplikasi Anda dengan pengguna yang menerima halaman kesalahan mewah
  • Percepat hal-hal dengan cache
  • Pengaturan berbutir halus yang biasanya Anda lakukan dengan proxy terbalik dan bukan dengan server aplikasi
Giovanni Toraldo
sumber
6

Anda dapat menggunakan program redir:

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

Gunakan sudo.

Konfigurasikan sudo agar pengguna biasa dapat menjalankan perintah yang sesuai:

/etc/init.d/httpd start

Atau

apachectl stop

Atau

/usr/local/apache2/apachectl restart

Atau

/myapp/myappbin start

(Atau perintah / skrip apa pun yang Anda gunakan untuk memulai / menghentikan server / aplikasi tertentu Anda)

Tidak sekarang
sumber
8
Ini memiliki masalah yang sama - menjalankan layanan karena root adalah praktik yang buruk.
Kevin Panko
4

jawaban cerah benar, tetapi Anda mungkin menghadapi masalah tambahan karena antarmuka loopback tidak menggunakan tabel PREROUTING,

jadi aturan iptables yang ditambahkan adalah dua:

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
sumber
3

Dengan Linux, Anda memiliki dua opsi lain:

Kedua ekstensi ke kernel Linux memungkinkan untuk memberikan hak akses pada tingkat yang sangat halus. Ini akan memungkinkan Anda untuk memberikan proses ini untuk membuka port 80 tetapi tidak akan mewarisi hak root lainnya.

Dari apa yang saya dengar, grsecurity jauh lebih mudah digunakan tetapi SELinux lebih aman.

Aaron Digulla
sumber
2

Salah satu solusinya adalah dengan menggunakan iptables untuk melakukan PAT pada paket untuk port 80. Anda dapat menggunakan ini untuk merutekan paket ke port 8080 lokal, misalnya. Pastikan dan sesuaikan paket keluar kembali ke port 80.

Dalam pengalaman saya, fitur perizinan berbutir halus dari Linux tidak dikompilasi menjadi kernel standar karena masalah keamanan.


sumber
2

Jika Anda mencoba melakukan ini sehingga perintah yang dijalankan pengguna dapat menggunakan port 80, maka satu-satunya solusi Anda adalah trik iptables atau pengaturan setuid-to-root yang dapat dieksekusi.

Cara sesuatu seperti Apache melakukan ini (ia mengikat ke port 80, tetapi berjalan sebagai orang lain selain root) adalah menjalankan sebagai root, mengikat ke port, kemudian mengubah kepemilikan proses ke pengguna yang tidak memiliki hak istimewa setelah port. sudah diatur. Jika aplikasi yang Anda tulis dapat dijalankan oleh root, Anda dapat membuatnya mengubah pemilik menjadi pengguna non-privat setelah port diatur. Tetapi jika ini hanya untuk pengguna biasa berjalan dari baris perintah, maka Anda harus menggunakan salah satu solusi lain.

rjray
sumber
2

Ketika saya memiliki berbagai aplikasi penyajian web (skrip python, mesin kucing jantan, ...) yang saya tidak ingin jalankan sebagai root, saya biasanya mengkonfigurasi server web apache di depannya. Apache mendengarkan port 80, dan kucing jantan mendengarkan 8080.

Di apache: s config:

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

Lihat dokumentasi mod-proxy untuk info lebih lanjut: http://httpd.apache.org/docs/2.2/mod/mod_proxy.html


sumber
1
Kelemahan dari solusi ini adalah hilangnya IP yang masuk di log Tomcat.
Emmanuel Bourg
2

Saya pikir solusi terbaik adalah dengan sgid aplikasi Anda dan segera setelah port-nya terikat, ia harus melepaskan hak istimewa dengan beralih ke pengguna lain.

Anxy Dicy
sumber
1

Beberapa sistem host tidak memungkinkan untuk menggunakan modul NAT, 'iptables' tidak menyelesaikan masalah dalam kasus ini.

Bagaimana dengan xinetd?

Dalam kasus saya (ubuntu 10.04)

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

Rekatkan konfigurasi:

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

Kemudian:

# service xinetd restart

http://docs.codehaus.org/display/JETTY/port80 menjelaskan lebih baik.

Thomas
sumber
1
Ini pada dasarnya setara dengan menempatkan proxy terbalik di depan server, tetapi itu agak tidak efisien dibandingkan dengan solusi khusus seperti HAproxy, Pound atau Varnish yang memahami protokol HTTP dan dapat menambahkan header yang berguna seperti X-Forwarded-For.
Emmanuel Bourg
-1

Sebagai tambahan, FreeBSD dan Solaris (ada yang ingat itu ?) Membiarkan Anda melakukan ini (mengikat port rendah) tanpa eskalasi hak istimewa (yaitu, menggunakan program untuk beralih ke root). Karena Anda menentukan Linux, saya hanya memposting ini sebagai pemberitahuan kepada orang lain yang mungkin menemukan pertanyaan ini.

Daniel C. Sobral
sumber
-1

Necromancing.

Sederhana. Dengan kernel normal atau lama, Anda tidak.
Seperti yang ditunjukkan oleh yang lain, iptables dapat meneruskan sebuah port.
Seperti yang ditunjukkan oleh yang lain, CAP_NET_BIND_SERVICE juga dapat melakukan pekerjaan itu.
Tentu saja CAP_NET_BIND_SERVICE akan gagal jika Anda meluncurkan program Anda dari skrip, kecuali jika Anda menetapkan batas pada penerjemah shell, yang tidak ada gunanya, Anda bisa menjalankan layanan Anda sebagai root ...
misalnya untuk Java, Anda harus menerapkannya ke JAVA JVM

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

Jelas, itu berarti setiap program Java dapat mengikat port sistem.
Dito untuk mono / .NET.

Saya juga cukup yakin xinetd bukan yang terbaik dari ide.
Tetapi karena kedua metode ini adalah peretasan, mengapa tidak hanya mengangkat batas dengan mengangkat batasan?
Tidak ada yang mengatakan Anda harus menjalankan kernel normal, jadi Anda bisa menjalankan kernel Anda sendiri.

Anda cukup mengunduh sumber untuk kernel terbaru (atau yang sama dengan yang Anda miliki saat ini). Setelah itu, Anda pergi ke:

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

Di sana Anda mencari baris ini

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

dan ubah ke

#define PROT_SOCK 0

jika Anda tidak ingin memiliki situasi ssh tidak aman, Anda mengubahnya menjadi ini: #define PROT_SOCK 24

Secara umum, saya akan menggunakan pengaturan terendah yang Anda butuhkan, misalnya 79 untuk http, atau 24 saat menggunakan SMTP pada port 25.

Itu saja.
Kompilasi kernel, dan instal.
Mulai ulang.
Selesai - batas bodoh itu PERLU, dan itu juga berfungsi untuk skrip.

Inilah cara Anda mengompilasi 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 ..

Singkatnya, gunakan iptables jika Anda ingin tetap aman, kompilasi kernel jika Anda ingin memastikan pembatasan ini tidak pernah mengganggu Anda lagi.

Kebingungan
sumber
Apakah seseorang tolong jelaskan downvotes? Kompilasi kernel tidak berfungsi? Atau apakah hanya karena setelah itu, Anda tidak dapat melakukan upgrade kernel dari repositori normal lagi?
Quandary
Saya mencoba solusi ini ( sudo setcap cap_net_bind_service=+ep /path-to-java/java) tetapi saya selalu mengerti java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directoryjika java memiliki set caps. lihat juga bagian pertama dari unix.stackexchange.com/a/16670/55508
Daniel Alder
1
Memecahkan kesalahan sebelumnya dengan menambahkan <javahome>/lib/amd64/jli/ke ld.so.confdan berjalansudo ldconfig
Daniel Alder