Kök olmayan işlemin 80 ve 443 numaralı bağlantı noktalarına bağlanmasına izin verilsin mi?


104

Bir kullanıcı programı programının 80 ve 443 numaralı bağlantı noktalarına bağlanmasını sağlamak için bir çekirdek parametresi ayarlamak mümkün müdür?

Sormamın nedeni, ayrıcalıklı bir sürecin soketi açıp dinlemesine izin vermesinin aptallığı olduğunu düşünüyorum. Soketi açan ve dinleyen herhangi bir şey yüksek risklidir ve yüksek riskli uygulamalar kök olarak çalışmamalıdır.

Kök ayrıcalıklarına sahip kötü amaçlı yazılımları kaldırmaya çalışmak yerine, 80 numaralı bağlantı noktasında ayrıcalıklı olmayan sürecin ne olduğunu anlamaya çalışmayı tercih ederim.



10
Uzun cevap tho evet .. yani kısa cevap da evet olmalı.
BT

4
Kısa cevap ise evet.
Jason C

Yanıtlar:


163

Buradaki diğer cevapların ve yorumların neden bahsettiğinden emin değilim. Bu oldukça kolay bir şekilde mümkün. Her ikisi de işlemi kökten yükseltmek zorunda kalmadan düşük numaralı bağlantı noktalarına erişime izin veren iki seçenek vardır:

Seçenek 1: CAP_NET_BIND_SERVICEBir işleme düşük numaralı bağlantı noktası erişimi vermek için kullanın:

Bu sayede, setcapkomutları kullanarak düşük numaralı bağlantı noktalarına bağlanmak için belirli bir ikili dosyaya kalıcı erişim sağlayabilirsiniz :

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

E / i / p kısmı hakkında daha fazla bilgi için, bkz cap_from_text.

Bunu yaptıktan sonra, /path/to/binarydüşük numaralandırılmış bağlantı noktalarına bağlanabilecektir. setcapBir sembolik bağlantı yerine ikili dosya üzerinde kullanmanız gerektiğini unutmayın .

Seçenek 2: Daha iyi authbindkullanıcı / grup / port kontrolü ile tek seferlik erişim vermek için kullanın :

authbind( Adam sayfa ) aracı bunun için kesin vardır.

  1. Yükleme authbindfavori paket yöneticisini kullanarak.

  2. İlgili bağlantı noktalarına erişim sağlayacak şekilde yapılandırın, örneğin tüm kullanıcılardan ve gruplardan 80 ve 443'e izin vermek için:

    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. Şimdi emrinizi şu şekilde uygulayın authbind(isteğe bağlı olarak --deepveya diğer argümanlar, man sayfasına bakın):

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

    Örneğin

    authbind --deep java -jar SomeServer.jar
    

Yukarıdakilerin her ikisinde de aşağı ve yukarı yön vardır. Seçenek 1, ikili dosyaya güven verir ancak bağlantı noktası başına erişim üzerinde kontrol sağlamaz. Seçenek 2, kullanıcıya / gruba güven verir ve port başına erişim üzerinde kontrol sağlar, ancak AFAIK, yalnızca IPv4'ü destekler.


Gerçekten rwxizne ihtiyacı var mı ?
matt

İşlemi Seçenek 1'de geri almak için, -pintead komutunu kullanarak komutu tekrar çalıştırır +eipmısınız?
eugene1832,

5
Setcap ile çalıştırılabilir dosyanın üzerine yazarsanız, ayrıcalıklar verdiğinizden emin olun (ör. Yeniden yapın), ayrıcalıklı port durumunu kaybeder ve yeniden ayrıcalıkları vermeniz gerekir: |
rogerdpack

1
Yapmam gereken şeyler; Ruby kullanan bir yakut çalıştırılabilir çalıştıran bir sysv hizmeti çalıştırmaya çalışıyordum. Versiyona özgü yakutun çalıştırılabilir kodunasetcap izin vermelisiniz , örneğin/usr/bin/ruby1.9.1
Christian Rondeau

3
chmod777'ye byportdosya atmanın en iyi fikir olduğuna şüphelerim var . Ben arasında değişen izin vermeden gördüğüm 500için 744. Sizin için çalışan en kısıtlayıcı olana sıkışırdım.
Pere

28

Dale Hagglund yerinde. Bu yüzden ben sadece aynı şeyi söyleyeceğim ama farklı bir şekilde, bazı özellikleri ve örnekleri ile. ☺

Unix ve Linux dünyalarında yapılacak doğru şey:

  • süper kullanıcı olarak çalışan ve dinleme soketini bağlayan küçük, basit, kolay denetlenebilir bir programa sahip olmak;
  • ilk programın doğurduğu, ayrıcalıkları azaltan başka bir küçük, basit, kolay denetlenebilir bir programa sahip olmak;
  • hizmet etinin ayrı bir üçüncü programda, süper kullanıcı olmayan bir hesap altında çalıştırılması ve ikinci program tarafından yüklenen zincirin çalıştırılması, soketin açık bir dosya tanımlayıcısının basitçe miras kalmasını beklemek.

Yüksek riskin nerede olduğu konusunda yanlış bir fikriniz var. Yüksek risk, ağdan okuma ve basit bir sokette açılış, bir limana bağlama ve çağrı yapma eylemlerinde okunmayanlara göre hareket etmektir listen(). Yüksek riskli gerçek iletişimi yapan bir hizmetin parçası. Açmak, parça bind()ve listen()o (bir ölçüde) bile bir kısmını ve accepts()yüksek riskli değildir ve süper şemsiyesi altında çalıştırılabilir. accept()Ağ üzerindeki güvenilmeyen yabancıların kontrolü altında olan verileri kullanmazlar (kaynak IP adresleri hariç ).

Bunu yapmanın birçok yolu var.

inetd

Dale Hagglund'in dediği gibi, eski "ağ sunucusu" inetdbunu yapar. Hizmet işleminin yürütüldüğü hesap, içindeki sütunlardan biridir inetd.conf. Dinleme parçasını ve bırakma ayrıcalıklarını, küçük ve kolayca denetlenebilen iki ayrı programa ayırmaz, ancak ana servis kodunu, exec()açık bir dosya tanımlayıcı ile ortaya koyduğu bir servis sürecinde ayrı bir programa ayırır. soket için.

Denetim zorluğu, bir programı yalnızca denetlemek zorunda olduğu için çok fazla bir sorun değildir. inetden önemli sorun çok fazla denetim yapmak değil, daha ziyade araçlara kıyasla basit ince taneli çalışma zamanı servis kontrolü sağlamadığıdır.

UCSPI-TCP ve Daemontools

Daniel J. Bernstein'in UCSPI-TCP ve daemontools paketleri birlikte kullanılmak üzere tasarlandı. Alternatif olarak, Bruce Guenter'ın büyük ölçüde eşdeğer daemontools-encore araç setini kullanabilirsiniz.

Soket dosya tanımlayıcısını açma ve ayrıcalıklı yerel bağlantı noktasına bağlama programı, tcpserverUCSPI-TCP'dir. Hem yapar listen()ve accept().

tcpserverSonra ya (protokol sunulmakta çünkü örneğinde olduğu gibi, "oturum" sonra süper kullanıcı olarak başlayan ve içerir, örneğin bir FTP veya bir SSH programı) kök ayrıcalıkları kendisi düşer veya bir hizmet programı olarak çoğaltılır setuidgidbir olduğunu Yalnızca ayrıcalıkları düşüren ve ardından hizmet programına zincir yükleri yükleyen kendi kendine yeten küçük ve kolayca denetlenebilir bir program (bu nedenle hiçbiri hiçbir zaman süper kullanıcı ayrıcalıklarıyla çalışmaz qmail-smtpd).

runBöylece bir servis betiği şöyle olabilir ( boş IDENT servisi sağlamak için bu kukla için):

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

nosh

Hayır paketim bunu yapmak için tasarlandı. Tıpkı setuidgiddiğerleri gibi küçük bir yardımcı programı var. Küçük bir fark, systemdstil "LISTEN_FDS" hizmetlerinin yanı sıra UCSPI-TCP hizmetlerinde de kullanılabilir olması, bu nedenle geleneksel tcpserverprogram iki ayrı programla değiştirildi: tcp-socket-listenve tcp-socket-accept.

Yine, tek amaçlı yardımcı programlar doğar ve zincirler birbirlerini yükler. Tasarımın ilginç yönlerinden biri, süper kullanıcı ayrıcalıklarını listen()daha önce veya daha önce bırakmasıdır accept(). İşte bunun runiçin bir senaryo qmail-smtpdtam olarak bunu yapar:

#!/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 \
'

Süper himayesinde yürütülmektedir programlar küçük hizmet agnostik zincir yükleme araçlardır fdmove, clearenv, envdir, softlimit, tcp-socket-listen, ve setuidgid. Başlanan noktaya shkadar soket açık ve smtplimana bağlı ve işlem artık süper kullanıcı haklarına sahip değil.

s6, s6 ağı ve execline

Laurent Bercot'un s6 ve s6 ağ paketleri, bunu birlikte yapacak şekilde tasarlanmıştır. Komutlar yapısal olarak daemontoolsve UCSPI-TCP'ye çok benzer .

runkomut konması dışında, hemen hemen aynı olacaktır s6-tcpserveriçin tcpserverve s6-setuidgidiçin setuidgid. Bununla birlikte, bir kişi M. Bercot'un yürütme araç setini aynı anda kullanmayı da seçebilir .

İşte Wayne Marshall'ın orijinalinden hafifçe değiştirilmiş, execline, s6, s6-networking ve publicfile'den FTP sunucusu programını kullanan bir FTP servisine örnek :

#!/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

Gerrit Pape en ipsvd ucspi-tcp ve s6-ağ ile aynı doğrultuda çalışan başka araç setidir. Araçlar chpstve tcpsvdbu sefer, ama aynı şeyi yapıyorlar ve güvenilmeyen istemciler tarafından ağ üzerinden gönderilen şeylerin okunması, işlenmesi ve yazılmasını yapan yüksek riskli kod hala ayrı bir programda.

İşte M. Pape'infnord bir runsenaryoda yayınlanması örneği :

#!/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

systemdBazı Linux dağıtımlarında bulunabilir yeni hizmet denetim ve init sistemi, ne amaçlanmaktadır inetdyapabilirsiniz . Ancak, küçük kendi kendine yeten programlar paketi kullanmaz. Kişi systemdne yazık ki bütünüyle denetlemek zorunda .

İle systemdbiri soket tanımlamak için yapılandırma dosyaları oluşturur systemddinler ve bir hizmeti systemdbaşlatır. Servis "birim" dosyası, hangi kullanıcı olarak çalıştığı da dahil olmak üzere servis işlemleri üzerinde büyük bir kontrol sağlamasına izin veren ayarlara sahiptir.

Bu kullanıcı süper kullanıcı olmayan bir kullanıcı olarak ayarlanmışsa systemd, soketin açılması, bir bağlantı noktasına bağlanması ve # 1 işleminde süper kullanıcı olarak çağırılması listen()(ve gerekirse accept()) ve kullanıcı tarafından servis işleminin yapılması spawns, kullanıcı ayrıcalığı olmadan çalışır.


2
İltifat için teşekkürler. Bu, somut bir tavsiye koleksiyonudur. +1.
Dale Hagglund

11

Benim daha farklı bir yaklaşımım var. Bir node.js sunucusu için 80 numaralı bağlantı noktasını kullanmak istedim. Node.js sudo olmayan bir kullanıcı için yüklendiğinden beri bunu yapamadım. Sembolik bağlantılar kullanmaya çalıştım, ama benim için işe yaramadı.

Daha sonra bağlantıları bir porttan diğer porta iletebileceğimi anladım. Böylece sunucuyu 3000 numaralı bağlantı noktasında başlattım ve 80 numaralı bağlantı noktasından 3000 numaralı bağlantı noktasını öne doğru bir bağlantı noktası kurdum.

Bu bağlantı , bunun için kullanılabilecek gerçek komutları sağlar. İşte komutlar -

localhost / geri döngü

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

dış

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

İkinci komutu kullandım ve bu benim için çalıştı. Bu yüzden bunun, kullanıcı işleminin alt bağlantı noktalarına doğrudan erişmesine izin vermek değil, bağlantı noktası iletmeyi kullanarak erişmelerini sağlamak için bir orta yol olduğunu düşünüyorum.


6
Kutunun dışında düşünmek için +1
Richard Wiseman

4

İçgüdüleriniz tamamen doğru: Kök olarak geniş bir karmaşık programın çalıştırılması kötü bir fikir, çünkü karmaşıklıkları onları güvenmeyi zorlaştırıyor.

Ancak, düzenli kullanıcıların ayrıcalıklı bağlantı noktalarına bağlanmasına izin vermek de kötü bir fikirdir, çünkü bu tür bağlantı noktaları genellikle önemli sistem hizmetlerini temsil eder.

Bu açık çelişkiyi çözmek için standart yaklaşım ayrıcalık ayrımıdır . Temel fikir, programınızı, her biri genel uygulamanın iyi tanımlanmış bir parçası olan ve basit sınırlı arabirimlerle iletişim kuran iki (veya daha fazla) bölüme ayırmaktır.

Verdiğiniz örnekte, programınızı iki parçaya ayırmak istiyorsunuz. Kök olarak çalışan ve açıp ayrıcalıklı sokete bağlanan ve daha sonra bir şekilde normal bir kullanıcı olarak çalışan diğer bölüme bağlar.

Bu ayrılığa ulaşmak için bu iki ana yol.

  1. Kök olarak başlayan tek bir program. Yaptığı ilk şey, mümkün olduğu kadar basit ve sınırlı bir şekilde gerekli soketi oluşturmaktır. Ardından, ayrıcalıkları bırakır, yani kendisini normal bir kullanıcı modu işlemine dönüştürür ve diğer tüm işleri yapar. Ayrıcalıkları doğru bir şekilde bırakmak, çok zordur, bu yüzden lütfen bunu doğru şekilde incelemek için zaman ayırın.

  2. Bir üst işlem tarafından oluşturulan bir soket çifti üzerinden iletişim kuran bir çift program. Ayrıcalıklı olmayan bir sürücü programı ilk argümanları alır ve belki de bazı temel argüman doğrulamalarını yapar. Socketpair () aracılığıyla bağlanmış soketler çifti oluşturur ve ardından asıl işi yapacak diğer iki programı çatallar ve yürütür ve soket çifti ile iletişim kurar. Bunlardan biri ayrıcalıklıdır ve sunucu soketini ve diğer ayrıcalıklı işlemleri yaratacaktır ve diğeri daha karmaşık ve bu nedenle daha güvenilir uygulama uygulamalarını gerçekleştirecektir.

[1] http://en.m.wikipedia.org/wiki/Privilege_separation


Teklifin en iyi uygulama olarak kabul edilmiyor. Ayrıcalıklı bir sokette dinleyebilecek inetd'e bakabilir ve ardından bu soketi ayrıcalıklı olmayan bir programa verebilirsiniz.
Dale Hagglund

3

En basit çözüm: Linux üzerindeki tüm ayrıcalıklı portları kaldırın

Ubuntu / debian üzerinde çalışır:

#save configuration permanently
echo 'net.ipv4.ip_unprivileged_port_start=0' > /etc/sysctl.d/50-unprivileged-ports.conf
#apply conf
sysctl --system

(rootBox hesabı olmayan VirtualBox için iyi çalışır)

Şimdi, güvenlik konusunda dikkatli olun çünkü tüm kullanıcılar tüm bağlantı noktalarını bağlayabilir!


Zekice. Bir küçük nit: konfigürasyon 80 ve 443'ü açar, fakat diğer tüm portları da açar. Diğer portlardaki gevşetme izinleri istenmeyebilir.
jww
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.