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" inetd
bunu 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. inetd
en ö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ı, tcpserver
UCSPI-TCP'dir. Hem yapar listen()
ve accept()
.
tcpserver
Sonra 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 setuidgid
bir 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
).
run
Bö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ı setuidgid
diğerleri gibi küçük bir yardımcı programı var. Küçük bir fark, systemd
stil "LISTEN_FDS" hizmetlerinin yanı sıra UCSPI-TCP hizmetlerinde de kullanılabilir olması, bu nedenle geleneksel tcpserver
program iki ayrı programla değiştirildi: tcp-socket-listen
ve 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 run
için bir senaryo qmail-smtpd
tam 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 sh
kadar soket açık ve smtp
limana 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 daemontools
ve UCSPI-TCP'ye çok benzer .
run
komut konması dışında, hemen hemen aynı olacaktır s6-tcpserver
için tcpserver
ve s6-setuidgid
iç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 chpst
ve tcpsvd
bu 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 run
senaryoda 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
systemd
Bazı Linux dağıtımlarında bulunabilir yeni hizmet denetim ve init sistemi, ne amaçlanmaktadır inetd
yapabilirsiniz . Ancak, küçük kendi kendine yeten programlar paketi kullanmaz. Kişi systemd
ne yazık ki bütünüyle denetlemek zorunda .
İle systemd
biri soket tanımlamak için yapılandırma dosyaları oluşturur systemd
dinler ve bir hizmeti systemd
baş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.