Saya menulis daemon server HTTP di C (ada alasan mengapa), mengelolanya dengan file unit systemd.
Saya menulis ulang aplikasi yang dirancang 20 tahun yang lalu, sekitar tahun 1995. Dan sistem yang mereka gunakan adalah mereka chroot dan kemudian setuid, dan prosedur standar.
Sekarang dalam pekerjaan saya sebelumnya, kebijakan yang biasa adalah bahwa Anda tidak pernah menjalankan proses apa pun sebagai root. Anda membuat pengguna / grup untuk itu dan lari dari sana. Tentu saja, sistem menjalankan beberapa hal sebagai root, tetapi kami dapat mencapai semua pemrosesan logika bisnis tanpa menjadi root.
Sekarang untuk daemon HTTP, saya bisa menjalankannya tanpa root jika saya tidak chroot di dalam aplikasi. Jadi bukankah lebih aman bagi aplikasi untuk tidak pernah berjalan sebagai root?
Bukankah lebih aman untuk menjalankannya sebagai pengguna mydaemon dari awal? Alih-alih memulai dengan root, chroot, lalu setuid ke pengguna mydaemon?
capabilities(7)
.Jawaban:
Tampaknya orang lain telah melewatkan poin Anda, yang bukan alasan mengapa menggunakan root yang diubah, yang tentu saja Anda sudah tahu, atau apa lagi yang dapat Anda lakukan untuk membatasi dæmons, ketika Anda juga jelas tahu tentang berlari di bawah naungan akun pengguna yang tidak memiliki hak pribadi; tetapi mengapa melakukan hal ini di dalam aplikasi . Sebenarnya ada contoh yang cukup tepat tentang alasannya.
Pertimbangkan desain
httpd
program demon dalam paket publik Daniel J. Bernstein. Hal pertama yang dilakukannya adalah mengubah root ke direktori root yang diperintahkan untuk digunakan dengan argumen perintah, lalu menjatuhkan hak istimewa ke ID pengguna dan ID grup unprivileged yang dilewatkan dalam dua variabel lingkungan.Toolset manajemen demon memiliki alat khusus untuk hal-hal seperti mengubah direktori root dan beralih ke ID pengguna dan grup yang tidak memiliki hak. Runit Gerrit Pape punya
chpst
. Toolset nosh saya memilikichroot
dansetuidgid-fromenv
. S6 Laurent Bercot memilikis6-chroot
dans6-setuidgid
. Perpecahan Wayne Marshall telahruntool
danrunuid
. Dan seterusnya. Memang, mereka semua memiliki toolset daemontools M. Bernstein sendirisetuidgid
sebagai anteseden.Orang akan berpikir bahwa seseorang dapat mengekstrak fungsionalitas dari
httpd
dan menggunakan alat khusus tersebut. Kemudian, seperti yang Anda bayangkan, tidak ada bagian dari program server yang pernah berjalan dengan hak pengguna super.Masalahnya adalah bahwa seseorang sebagai konsekuensi langsung harus melakukan lebih banyak pekerjaan secara signifikan untuk mengatur root yang diubah, dan ini memunculkan masalah baru.
Dengan
httpd
berdirinya Bernstein , satu - satunya file dan direktori yang ada di pohon direktori root adalah yang akan dipublikasikan ke dunia. Tidak ada yang lain di pohon itu sama sekali. Selain itu, tidak ada alasan untuk setiap executable file program gambar ada di pohon itu.Tapi memindahkan perubahan direktori root keluar ke dalam program rantai-loading (atau systemd), dan tiba-tiba file program gambar untuk
httpd
, setiap shared library yang banyak, dan setiap file khusus di/etc
,/run
, dan/dev
bahwa program loader atau C runtime akses perpustakaan selama inisialisasi program (yang mungkin Anda temukan cukup mengejutkan jika Andatruss
/strace
program C atau C ++), juga harus ada di root yang diubah. Kalauhttpd
tidak, tidak bisa dirantai ke dan tidak akan memuat / menjalankan.Ingat bahwa ini adalah server konten HTTP (S). Ini berpotensi melayani file apa pun (yang dapat dibaca dunia) di root yang diubah. Ini sekarang termasuk hal-hal seperti perpustakaan Anda bersama, program loader Anda, dan salinan berbagai file konfigurasi loader / CRTL untuk sistem operasi Anda. Dan jika oleh beberapa (kebetulan) berarti server konten memiliki akses untuk menulis hal-hal, server yang dikompromikan mungkin dapat memperoleh akses tulis ke gambar program untuk
httpd
dirinya sendiri, atau bahkan program loader sistem Anda. (Ingat bahwa Anda sekarang memiliki dua set paralel/usr
,/lib
,/etc
,/run
, dan/dev
direktori untuk menjaga aman.)Tidak satu pun dari ini adalah kasus di mana
httpd
perubahan root dan drop hak istimewa itu sendiri.Jadi, Anda telah diperdagangkan dengan sejumlah kecil kode istimewa, yang cukup mudah diaudit dan berjalan tepat di awal
httpd
program, berjalan dengan hak pengguna super; karena memiliki permukaan serangan yang sangat luas dari file dan direktori di dalam root yang diubah.Inilah sebabnya mengapa tidak sesederhana melakukan segala sesuatu secara eksternal pada program layanan.
Perhatikan bahwa ini adalah fungsionalitas minimum di dalamnya
httpd
. Semua kode yang melakukan hal-hal seperti melihat dalam database akun sistem operasi untuk ID pengguna dan ID grup untuk dimasukkan ke dalam variabel lingkungan di tempat pertama adalah eksternal untukhttpd
program, dalam perintah sederhana mandiri yang dapat diaudit sepertienvuidgid
. (Dan tentu saja itu adalah alat ucspi, sehingga tidak mengandung kode untuk mendengarkan pada port TCP yang relevan (s) atau untuk menerima koneksi, mereka menjadi domain dari perintah sepertitcpserver
,tcp-socket-listen
,tcp-socket-accept
,s6-tcpserver4-socketbinder
,s6-tcpserver4d
, dan sebagainya.)Bacaan lebih lanjut
httpd
. file publik . cr.yp.to.httpd
. Perangkat lunak Daniel J. Bernstein semuanya dalam satu . Perangkat lunak. Jonathan de Boyne Pollard. 2016gopherd
. Perangkat lunak Daniel J. Bernstein semuanya dalam satu . Perangkat lunak. Jonathan de Boyne Pollard. 2017sumber
Saya pikir banyak detail pertanyaan Anda dapat berlaku sama
avahi-daemon
, yang saya lihat baru-baru ini. (Saya mungkin melewatkan detail lain yang berbeda). Menjalankan avahi-daemon dalam chroot memiliki banyak keuntungan, seandainya avahi-daemon terganggu. Ini termasuk:Poin 3 bisa sangat bagus ketika Anda tidak menggunakan dbus atau serupa ... Saya pikir avahi-daemon menggunakan dbus, jadi pastikan untuk menjaga akses ke sistem dbus bahkan dari dalam chroot. Jika Anda tidak memerlukan kemampuan untuk mengirim pesan pada sistem dbus, menyangkal kemampuan itu mungkin fitur keamanan yang cukup bagus.
Perhatikan bahwa jika avahi-daemon ditulis ulang, itu berpotensi dapat memilih untuk mengandalkan systemd untuk keamanan, dan menggunakan mis
ProtectHome
. Saya mengusulkan perubahan ke avahi-daemon untuk menambahkan perlindungan ini sebagai lapisan tambahan, bersama dengan beberapa perlindungan tambahan yang tidak dijamin oleh chroot. Anda dapat melihat daftar opsi lengkap yang saya usulkan di sini:https://github.com/lathiat/avahi/pull/181/commits/67a7b10049c58d6afeebdc64ffd2023c5a93d49a
Sepertinya ada lebih banyak batasan yang bisa saya gunakan jika avahi-daemon tidak menggunakan chroot itu sendiri, beberapa di antaranya disebutkan dalam pesan commit. Saya tidak yakin seberapa banyak ini berlaku.
Catatan, perlindungan yang saya gunakan tidak akan membatasi daemon dari membuka file unix socket (poin 3 di atas).
Pendekatan lain adalah menggunakan SELinux. Namun Anda akan mengikat aplikasi Anda ke sub-set distribusi Linux. Alasan saya memikirkan SELinux secara positif di sini, adalah bahwa SELinux membatasi akses yang dimiliki proses pada dbus, dengan cara yang halus. Sebagai contoh, saya pikir Anda sering berharap bahwa
systemd
tidak ada dalam daftar nama bus yang Anda butuhkan untuk dapat mengirim pesan ke :-)."Aku bertanya-tanya, apakah menggunakan systemd sandboxing lebih aman daripada chroot / setuid / umask / ..."
Ringkasan: mengapa tidak keduanya? Mari kita decode sedikit di atas :-).
Jika Anda berpikir tentang poin 3, menggunakan chroot memberikan lebih banyak kurungan. ProtectHome = dan teman-temannya bahkan tidak berusaha seketat chroot. (Misalnya, tidak ada daftar nama sistemd opsi blacklist
/run
, di mana kita cenderung meletakkan file socket unix).chroot menunjukkan bahwa membatasi akses sistem file bisa menjadi sangat kuat, tetapi tidak semua Linux adalah file :-). Ada opsi systemd yang dapat membatasi hal-hal lain, yang bukan file. Ini berguna jika program ini dikompromikan, Anda dapat mengurangi fitur kernel yang tersedia untuknya, yang mungkin mencoba untuk mengeksploitasi kerentanan masuk. Misalnya avahi-daemon tidak memerlukan soket bluetooth dan saya kira server web Anda juga tidak :-). Jadi jangan berikan itu akses ke keluarga alamat AF_BLUETOOTH. Hanya daftar putih AF_INET, AF_INET6, dan mungkin AF_UNIX, menggunakan
RestrictAddressFamilies=
opsi.Silakan baca dokumen untuk setiap opsi yang Anda gunakan. Beberapa opsi menjadi lebih efektif dalam kombinasi dengan yang lain, dan beberapa tidak tersedia pada semua arsitektur CPU. (Bukan karena CPU buruk, tetapi karena port Linux untuk CPU itu tidak dirancang dengan baik. Saya pikir).
(Ada prinsip umum di sini. Lebih aman jika Anda dapat menulis daftar apa yang ingin Anda izinkan, bukan apa yang ingin Anda tolak. Seperti mendefinisikan chroot memberi Anda daftar file yang diizinkan untuk diakses, dan ini lebih kuat daripada mengatakan Anda ingin memblokir
/home
).Pada prinsipnya, Anda bisa menerapkan sendiri semua pembatasan yang sama sebelum setuid (). Itu semua hanya kode yang dapat Anda salin dari systemd. Namun, opsi unit systemd harus secara signifikan lebih mudah untuk ditulis, dan karena mereka berada dalam format standar, mereka harus lebih mudah dibaca dan ditinjau.
Jadi saya bisa sangat merekomendasikan hanya membaca bagian sandboxing
man systemd.exec
pada platform target Anda. Tetapi jika Anda ingin desain yang paling aman mungkin, saya tidak akan takut untuk mencobachroot
(dan kemudian menjatuhkanroot
hak istimewa) dalam program Anda juga . Ada pengorbanan di sini. Penggunaanchroot
memberi beberapa kendala pada desain keseluruhan Anda. Jika Anda sudah memiliki desain yang menggunakan chroot, dan tampaknya melakukan apa yang Anda butuhkan, itu terdengar sangat hebat.sumber
Jika Anda dapat mengandalkan systemd, maka memang lebih aman (dan lebih sederhana!) Untuk meninggalkan sandboxing ke systemd. (Tentu saja, aplikasi juga dapat mendeteksi apakah telah diluncurkan sandbox oleh systemd atau tidak, dan sandbox itu sendiri jika masih root.) Setara dengan layanan yang Anda gambarkan adalah:
Tapi kita tidak harus berhenti di situ. systemd juga dapat melakukan banyak sandboxing lain untuk Anda - berikut adalah beberapa contoh:
Lihat
man 5 systemd.exec
lebih banyak arahan dan deskripsi lebih rinci. Jika Anda membuat soket daemon Anda dapat diaktifkan (man 5 systemd.socket
), Anda bahkan dapat menggunakan opsi yang berhubungan dengan jaringan: satu-satunya tautan layanan ke dunia luar adalah soket jaringan yang diterima dari systemd, itu tidak akan dapat terhubung ke hal lain. Jika ini adalah server sederhana yang hanya mendengarkan pada beberapa port dan tidak perlu terhubung ke server lain, ini bisa bermanfaat. (Opsi terkait sistem file juga dapat membuatRootDirectory
usang, menurut saya, jadi mungkin Anda tidak perlu repot mengatur direktori root baru dengan semua biner dan perpustakaan yang diperlukan lagi.)Versi systemd yang lebih baru (sejak v232) juga mendukung
DynamicUser=yes
, di mana systemd akan secara otomatis mengalokasikan pengguna layanan untuk Anda hanya untuk runtime layanan. Ini berarti Anda tidak perlu mendaftarkan pengguna permanen untuk layanan, dan bekerja dengan baik selama layanan tidak menulis ke lokasi sistem file lain dibandingkanStateDirectory
,LogsDirectory
danCacheDirectory
(yang Anda juga dapat mendeklarasikan dalam file Unit - lihatman 5 systemd.exec
, lagi - dan systemd yang kemudian akan mengatur, berhati-hati untuk menempatkan mereka dengan benar ke pengguna dinamis).sumber