Dale Hagglund tepat. Jadi saya hanya akan mengatakan hal yang sama tetapi dengan cara yang berbeda, dengan beberapa spesifik dan contoh. ☺
Hal yang benar untuk dilakukan di dunia Unix dan Linux adalah:
- untuk memiliki program kecil, sederhana, mudah diaudit, yang berfungsi sebagai superuser dan mengikat soket pendengaran;
- untuk memiliki program kecil, sederhana, mudah diaudit, yang menghilangkan hak istimewa, yang dihasilkan oleh program pertama;
- untuk mendapatkan daging dari layanan, dalam program ketiga yang terpisah , berjalan di bawah akun non-superuser dan rantai dimuat oleh program kedua, berharap untuk hanya mewarisi deskriptor file terbuka untuk soket.
Anda memiliki gagasan yang salah tentang di mana risiko tinggi berada. Risiko tinggi adalah membaca dari jaringan dan bertindak berdasarkan apa yang dibaca bukan dalam tindakan sederhana membuka soket, mengikatnya ke port, dan menelepon listen()
. Ini adalah bagian dari layanan yang melakukan komunikasi aktual yang berisiko tinggi. Bagian-bagian yang membuka,, bind()
dan listen()
, dan bahkan (sampai batas tertentu) bagian itu accepts()
, tidak berisiko tinggi dan dapat dijalankan di bawah pengawasan superuser. Mereka tidak menggunakan dan bertindak atas (dengan pengecualian alamat IP sumber dalam accept()
kasus ini) data yang berada di bawah kendali orang asing yang tidak dipercaya melalui jaringan.
Ada banyak cara untuk melakukan ini.
inetd
Seperti kata Dale Hagglund, "superserver jaringan" lama inetd
melakukan ini. Akun tempat proses layanan dijalankan adalah salah satu kolom di inetd.conf
. Itu tidak memisahkan bagian mendengarkan dan bagian hak istimewa jatuh ke dalam dua program terpisah, kecil dan mudah diaudit, tetapi itu memisahkan kode layanan utama menjadi program terpisah, exec()
ed dalam proses layanan yang muncul dengan deskriptor file terbuka untuk soket.
Kesulitan mengaudit tidak begitu menjadi masalah, karena seseorang hanya perlu mengaudit satu program. inetd
Masalah utama adalah tidak terlalu banyak mengaudit tetapi lebih karena tidak memberikan kontrol layanan runtime sederhana yang halus, dibandingkan dengan alat yang lebih baru.
UCSPI-TCP dan daemontools
Paket UCSPI-TCP dan daemontools dari Daniel J. Bernstein dirancang untuk melakukan hal ini bersamaan. Satu alternatif dapat menggunakan toolset daemontools-encore Bruce Guenter yang sebagian besar setara .
Program untuk membuka deskriptor file socket dan mengikat ke port lokal istimewa adalah tcpserver
, dari UCSPI-TCP. Itu baik listen()
dan accept()
.
tcpserver
kemudian memunculkan salah satu program layanan yang menjatuhkan hak root itu sendiri (karena protokol yang dilayani melibatkan mulai sebagai superuser dan kemudian "masuk", seperti halnya dengan, misalnya, FTP atau daemon SSH) atau setuidgid
yang merupakan program kecil mandiri dan mudah diaudit yang semata-mata menjatuhkan hak istimewa dan kemudian mengaitkan muatan ke program layanan dengan semestinya (tidak ada bagian yang dengan demikian dijalankan dengan hak pengguna super, seperti halnya dengan, katakanlah, qmail-smtpd
).
Jadi run
skrip layanan misalnya (ini untuk dummyidentd karena menyediakan layanan IDENT nol):
#!/bin/sh -e
exec 2>&1
exec \
tcpserver 0 113 \
setuidgid nobody \
dummyidentd.pl
tidak
Paket nosh saya dirancang untuk melakukan ini. Ini memiliki setuidgid
utilitas kecil , sama seperti yang lain. Satu perbedaan kecil adalah bahwa itu dapat digunakan dengan systemd
-style "LISTEN_FDS" layanan serta dengan layanan UCSPI-TCP, sehingga tcpserver
program tradisional digantikan oleh dua program terpisah: tcp-socket-listen
dan tcp-socket-accept
.
Sekali lagi, utilitas serba guna menelurkan dan saling memuat satu sama lain. Satu kekhasan desain yang menarik adalah bahwa seseorang dapat kehilangan hak superuser setelah listen()
tetapi bahkan sebelum accept()
. Berikut run
skrip untuk qmail-smtpd
itu memang melakukan hal itu:
#!/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 \
'
Program yang dijalankan di bawah naungan superuser adalah alat rantai-loading layanan-agnostik kecil fdmove
, clearenv
, envdir
, softlimit
, tcp-socket-listen
, dan setuidgid
. Pada titik yang sh
dimulai, soket terbuka dan terikat ke smtp
port, dan proses tidak lagi memiliki hak pengguna super.
s6, s6-networking, dan execline
Paket jaringan s6 dan s6 Laurent Bercot dirancang untuk melakukan hal ini bersamaan. Perintah-perintah secara struktural sangat mirip dengan daemontools
dan dari UCSPI-TCP.
run
skrip akan sama, kecuali untuk pengganti s6-tcpserver
untuk tcpserver
dan s6-setuidgid
untuk setuidgid
. Namun, orang mungkin juga memilih untuk menggunakan toolset execline M. Bercot pada saat yang sama.
Berikut ini adalah contoh dari layanan FTP, sedikit dimodifikasi dari aslinya Wayne Marshall , yang menggunakan execline, s6, s6-networking, dan program server FTP dari publicfile :
#!/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
Ipsvd Gerrit Pape adalah toolset lain yang berjalan di sepanjang jalur yang sama dengan ucspi-tcp dan s6-networking. Alatnya ada chpst
dan tcpsvd
kali ini, tetapi mereka melakukan hal yang sama, dan kode risiko tinggi yang melakukan pembacaan, pemrosesan, dan penulisan hal-hal yang dikirim melalui jaringan oleh klien yang tidak terpercaya masih dalam program terpisah.
Berikut contoh M. Pape menjalankan fnord
dalam run
skrip:
#!/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
, pengawasan layanan baru dan sistem init yang dapat ditemukan di beberapa distribusi Linux, dimaksudkan untuk melakukan apa yang inetd
bisa dilakukan . Namun, itu tidak menggunakan serangkaian program mandiri kecil. systemd
Sayangnya, kita harus mengaudit secara keseluruhan.
Dengan systemd
satu menciptakan file konfigurasi untuk menentukan soket yang systemd
mendengarkan, dan layanan yang systemd
dimulai. File "unit" layanan memiliki pengaturan yang memungkinkan seseorang mengendalikan proses layanan, termasuk pengguna yang dijalankannya.
Dengan pengguna yang ditetapkan sebagai bukan pengguna super, systemd
melakukan semua pekerjaan membuka soket, mengikatnya ke port, dan memanggil listen()
(dan, jika perlu, accept()
) dalam proses # 1 sebagai superuser, dan proses layanan yang dilakukan memunculkan berjalan tanpa hak pengguna super.