Uygulamam en başından daha düşük bir düzeyde çalışabiliyorsa neden güvenlik için korumalı alan oluşturmaya çalıştım?


14

C bir HTTP sunucusu arka plan programı (nedenleri vardır) yazarak, systemd birim dosyası ile yönetiyorum.

Ben 20 yıl önce, 1995 civarında tasarlanmış bir uygulamayı yeniden yazıyorum. Ve kullandıkları sistem, daha sonra krom ve sonra setuid ve standart prosedür olmasıdır.

Şimdi önceki çalışmamda, genel politika, hiçbir zaman kök olarak herhangi bir işlem yürütmemenizdi. Bunun için bir kullanıcı / grup oluşturup oradan çalıştırıyorsunuz. Tabii ki, sistem bazı şeyleri kök olarak çalıştırdı, ancak tüm iş mantığı işlemlerini kök olmadan gerçekleştirebiliriz.

Şimdi HTTP arka plan programı için, uygulamanın içinde krokim yoksa kök olmadan çalıştırabilirim. Yani uygulamanın hiç root olarak çalışması daha güvenli değil mi?

Başından beri mydaemon kullanıcısı olarak çalıştırmak daha güvenli değil mi? Kök ile başlatmak, köklendirme yapmak, sonra mydaemon kullanıcısına setuid?


3
80 veya 443 numaralı bağlantı noktasını kullanmak için root olarak çalıştırılmanız gerekir. aksi takdirde, tomcat ve diğer webapp / web sunucusu yazılımlarının yaptıklarını yapabilir ve daha yüksek bir bağlantı noktasında (örneğin, 8080, 9090, vb.) apache / nginx'i web sunucusu yazılımınızla olan bağlantıyı proxy yapmak için veya sistemin güvenlik duvarını 80 numaralı bağlantı noktasından web sunucunuza NAT / iletmek için kullanın. 80 veya 443 numaralı bağlantı noktasına ihtiyacınız yoksa veya bağlantıyı proxy veya yönlendirme yapabiliyorsanız, o zaman root olarak, bir chroot ya da başka bir şekilde çalıştırmanız gerekmez.
SnakeDoc

3
Linux'ta @SnakeDoc artık doğru değil. Teşekkürler capabilities(7).
0xC0000022L

@SnakeDoc kullanabilirsiniz authbind yanı
Abdul Ahad

Yanıtlar:


27

Görünüşe göre diğerleri fikrinizi kaçırdı, bu da değişmiş kökleri kullanmanın nedenleri değildi, elbette zaten açıkça biliyorsunuz ya da dæmons'ın sınırlarını koymak için başka ne yapabilirsiniz? ayrıcalıklı olmayan kullanıcı hesapları; ama neden uygulama içinde bu şeyler yapmak . Aslında bunun oldukça önemli bir örneği var.

httpdDaniel J. Bernstein'nin genel dosya paketindeki dæmon programının tasarımını düşünün . Yaptığı ilk şey, root komutunu komut argümanıyla kullanması söylenen kök dizine değiştirmek, ardından iki ortam değişkeninde iletilen ayrıcalıksız kullanıcı kimliğine ve grup kimliğine ayrıcalık bırakmaktır.

Dæmon yönetim araç setlerinde kök dizini değiştirme ve ayrıcalıklı olmayan kullanıcı ve grup kimliklerine düşme gibi şeyler için özel araçlar bulunur. Gerrit Pape'in runiti var chpst. Benim nosh araç takımım var chrootve setuidgid-fromenv. Laurent Bercot'un s6'sı s6-chrootve s6-setuidgid. Wayne Marshall'ın Perp'i var runtoolve runuid. Ve böylece. Gerçekten de hepsinin setuidgidöncül olarak M. Bernstein'ın kendi daemontools araç takımı vardır .

Kişi, işlevsellikleri httpdbu tür araçlardan çıkarabilir ve kullanabilir. Sonra, öngördüğünüz gibi , sunucu programının hiçbir bölümü süper kullanıcı ayrıcalıklarıyla çalışmaz.

Sorun şu ki, doğrudan bir sonuç olarak, değişen kökü kurmak için önemli ölçüde daha fazla iş yapılması gerekiyor ve bu yeni sorunları ortaya çıkarıyor.

Bernstein httpdolduğu gibi , kök dizin ağacındaki tek dosya ve dizinler dünyaya yayınlanacak olanlardır. Orada başka bir şey hiç ağacında. Ayrıca, bu ağaçta yürütülebilir herhangi bir program görüntü dosyasının bulunmasına gerek yoktur.

Ama bir zincir yükleme programı (veya systemd) içine kök dizin değişikliği dışarı taşımak ve için aniden programı görüntü dosyası httpd, paylaşılan herhangi kütüphaneler öyle yükler ve herhangi bir özel dosyaları /etc, /runve /devprogram yükleme veya C kütüphanesi erişime çalışma zamanı olduğunu program başlatma sırasında (siz truss/ stracea C veya C ++ programını kullanıyorsanız oldukça şaşırtıcı bulabilirsiniz ), değişen kökte de bulunmanız gerekir. Aksi takdirde httpdzincirleme yapılamaz ve yüklenemez / çalıştırılmaz.

Bunun bir HTTP (S) içerik sunucusu olduğunu unutmayın. Değişen kökte (dünya tarafından okunabilir) herhangi bir dosyayı sunabilir. Bu, artık paylaşılan kitaplıklarınız, program yükleyiciniz ve işletim sisteminiz için çeşitli yükleyici / CRTL yapılandırma dosyalarının kopyaları gibi şeyleri içerir. Ve bazılarının (yanlışlıkla) içerik sunucusunun bir şeyler yazma erişimi olduğu anlamına gelirse , güvenliği ihlal edilmiş bir sunucu muhtemelen program görüntüsünün httpdkendisi veya hatta sisteminizin program yükleyicisi için yazma erişimi kazanabilir . (Artık iki paralel setleri unutmayın /usr, /lib, /etc, /run, ve /devdizinleri güvenli tutmak için.)

Bunların hiçbiri httpdkökün değişmediği ve ayrıcalıkların kendini bıraktığı durum değildir.

Bu yüzden, denetlenmesi oldukça kolay olan ve httpdprogramın hemen başında çalışan ve süper kullanıcı ayrıcalıklarıyla çalışan az miktarda ayrıcalıklı kodla işlem gördünüz ; değiştirilmiş kök içinde dosya ve dizinlerin büyük ölçüde genişletilmiş saldırı yüzeyine sahip oldukları için.

Bu nedenle, hizmet programına harici olarak her şeyi yapmak kadar basit değildir.

Bununla birlikte, bunun httpdkendi içinde minimum bir işlevsellik olduğuna dikkat edin . Böyle ilk etapta bu ortam değişkenleri içine koymak için kullanıcı kimliği ve grup kimliği için işletim sisteminin hesap veritabanında görünüm olarak şeyler yapar kod tüm olduğu için harici httpdgibi basit bağımsız denetlenebilir komutlar, programa envuidgid. (Ve elbette bir UCSPI aracıdır, bu nedenle ilgili TCP bağlantı noktalarını dinlemek veya bağlantıları kabul etmek için kodlardan hiçbirini içermez tcpserver;tcp-socket-listen , tcp-socket-accept, s6-tcpserver4-socketbinder, s6-tcpserver4d, vb.)

daha fazla okuma


+1, tahsil edildiği gibi suçlu. Başlığı ve son paragrafı belirsiz buldum ve eğer haklıysan noktayı kaçırdım. Bu cevap çok pratik bir yorum veriyor. Şahsen, açıkça bu şekilde chroot ortamı oluşturmak zorunda kalmanın, çoğu insanın kaçınmak isteyeceği ekstra bir çaba olduğunu not ediyorum. Ancak buradaki 2 güvenlik noktası zaten iyi yapılmış.
sourcejedi

Hatırlanması gereken bir diğer nokta, sunucu herhangi bir ağ trafiğini işlemeden önce ayrıcalık bırakması durumunda, ayrıcalıklı kodun uzaktan istismarlara maruz kalmamasıdır.
kasperd

5

Sorunuzun birçok ayrıntısının avahi-daemon, son zamanlarda baktığım gibi aynı derecede geçerli olabileceğini düşünüyorum . (Gerçi farklı bir ayrıntı kaçırmış olabilir). Avahi-daemon'un bir krootta çalıştırılmasının birçok avantajı vardır, avahi-daemon'un tehlikeye girmesi durumunda. Bunlar:

  1. herhangi bir kullanıcının giriş dizinini okuyamaz ve özel bilgileri genişletemez.
  2. / tmp dosyasına yazarak diğer programlardaki hataları kullanamaz. Bu tür hataların en az bir kategorisi vardır. Örneğin https://www.google.co.uk/search?q=tmp+race+security+bug
  3. diğer cinlerin dinlediği ve mesajları okuyabileceği, kök dışında olan herhangi bir unix soket dosyasını açamaz.

Nokta 3, dbus veya benzeri bir şey kullanmadığınızda özellikle güzel olabilir ... Bence avahi-daemon dbus kullanıyor, bu yüzden sistem dbus'a bile krobin içinden erişmeyi sürdürüyor. Sistem dbus'ına mesaj gönderme yeteneğine ihtiyacınız yoksa, bu yeteneğin reddedilmesi oldukça güzel bir güvenlik özelliği olabilir.

systemd birim dosyası ile yönetme

Avahi-daemon yeniden yazıldıysa, güvenlik için systemd'ye güvenmeyi ve ör ProtectHome. Bu korumaları fazladan bir katman olarak eklemek için avahi-daemon'da bir değişiklik önerdim, bunun yanında chroot tarafından garanti edilmeyen bazı ek korumalar da önerdim. Burada önerdiğim seçeneklerin tam listesini görebilirsiniz:

https://github.com/lathiat/avahi/pull/181/commits/67a7b10049c58d6afeebdc64ffd2023c5a93d49a

Avahi-cin yaptıysam kullanmış olabilir daha kısıtlamalar vardır gibi görünüyor değil sözü bunlardan bazıları chroot kendisini kullanın mesajı işlemek. Bunun ne kadar geçerli olduğundan emin değilim.

Unutmayın, kullandığım korumalar, arka plan programının unix soket dosyalarını açmasını kısıtlamazdı (yukarıdaki 3. nokta).

Başka bir yaklaşım SELinux kullanmak olacaktır. Ancak, uygulamanızı Linux dağıtımlarının bu alt kümesine bağlıyorsunuz. SELinux'u burada olumlu olarak düşünmemizin nedeni, SELinux'un süreçlerin dbus üzerindeki erişimini ince bir şekilde kısıtlamasıdır. Örneğin, sık sık systemd:-) mesaj göndermek için gereken otobüs isimleri listesinde olmayacağını bekleyebilirsiniz düşünüyorum .

"Systemd sandboxing'i chroot / setuid / umask / ... 'dan daha güvenli kullanıyorsanız merak ediyordum."

Özet: neden ikisi de olmasın? Yukarıda biraz çözelim :-).

3. noktayı düşünürseniz, chroot kullanmak daha fazla sınırlama sağlar. ProtectHome = ve arkadaşları kroot kadar kısıtlayıcı olmaya bile çalışmazlar. (Örneğin, adlandırılmış sistemd seçeneklerinden hiçbiri, /rununix soket dosyaları koyma eğiliminde olduğumuz kara listelerdir ).

chroot, dosya sistemi erişimini kısıtlamanın çok güçlü olabileceğini, ancak Linux'taki her şeyin bir dosya olmadığını gösteriyor :-). Dosya olmayan diğer şeyleri kısıtlayabilen systemd seçenekleri vardır. Bu, programın tehlikeye girmesi durumunda, içindeki bir güvenlik açığından yararlanmaya çalışabileceği çekirdek özelliklerini azaltabilirsiniz. Örneğin avahi-daemon'un bluetooth yuvalarına ihtiyacı yoktur ve sanırım web sunucunuz da :-). Bu yüzden AF_BLUETOOTH adres ailesine erişim izni vermeyin. Sadece RestrictAddressFamilies=seçeneği kullanarak AF_INET, AF_INET6 ve belki AF_UNIX'i beyaz listeye ekleyin .

Lütfen kullandığınız her seçenek için dokümanları okuyun. Bazı seçenekler diğerleriyle birlikte daha etkilidir ve bazıları tüm CPU mimarilerinde kullanılamaz. (CPU kötü olduğu için değil, bu CPU'nun Linux portu o kadar iyi tasarlanmadığı için.

(Burada genel bir ilke vardır. Reddetmek istediklerinize değil, izin vermek istediklerinizin listesini yazabiliyorsanız daha güvenlidir. Bir chroot tanımlamak size erişmenize izin verilen dosyaların listesini verir ve bu daha sağlamdır engellemek istediğini söylemekten daha /home ).

Prensip olarak, setuid () yönteminden önce aynı kısıtlamaları kendiniz uygulayabilirsiniz. Tüm bunlar sadece systemd'den kopyalayabileceğiniz bir kod. Ancak, systemd birim seçeneklerinin yazılması çok daha kolay olmalı ve standart biçimde olduklarından okunması ve gözden geçirilmesi daha kolay olmalıdır.

Bu nedenle man systemd.exec, hedef platformunuzdaki korumalı alan bölümünü okumanızı şiddetle tavsiye ederim . Ancak mümkün olan en güvenli tasarımı istiyorsanız, programınızda da denemek chroot(ve sonra rootayrıcalık bırakmak ) için korkmazdım . Burada bir ödünleşme var. Kullanımı genel tasarımınıza bazı kısıtlamalar getirir. Zaten chroot kullanan bir tasarımınız varsa ve ihtiyacınız olanı yapıyor gibi görünüyorsa, kulağa harika geliyor.chroot


Özellikle sistem önerileri için +1.
mattdm

Ben akışı üzerinden yığını birden fazla cevap izin, ben de ur kabul ediyorum, ben ur cevap biraz öğrendim. Merak ediyorum, eğer systemd sandboxing'i chroot / setuid / umask / ... 'den daha güvenli kullanıyorsanız
mur

@mur sevdim sevindim :). Bu cevabım için çok doğal bir cevap. Bu yüzden sorunuzu cevaplamaya çalışmak için tekrar güncelledim.
sourcejedi

1

Systemd'ye güvenebiliyorsanız, kum havuzunu sistemd'e bırakmak daha güvenlidir (ve daha basittir!). (Tabii ki, uygulama ayrıca systemd tarafından korumalı olarak başlatılıp başlatılmadığını ve hala kökse korumalı alanın kendisini başlatır mı algılayabilir.) Açıkladığınız hizmetin eşdeğeri şöyle olacaktır:

[Service]
ExecStart=/usr/local/bin/mydaemon
User=mydaemon-user
RootDirectory=...

Ama burada durmak zorunda değiliz. systemd sizin için çok sayıda başka sanal alan da yapabilir - işte bazı örnekler:

[Service]
# allocate separate /tmp and /var/tmp for the service
PrivateTmp=yes
# mount / (except for some subdirectories) read-only
ProtectSystem=strict
# empty /home, /root
ProtectHome=yes
# disable setuid and other privilege escalation mechanisms
NoNewPrivileges=yes
# separate network namespace with only loopback device
PrivateNetwork=yes
# only unix domain sockets (no inet, inet6, netlink, …)
RestrictAddressFamilies=AF_UNIX

Bkz man 5 systemd.execçok daha fazla direktifleri ve daha ayrıntılı açıklamaları için. Daemon soketinizi etkinleştirilebilir ( man 5 systemd.socket) yaparsanız, ağla ilgili seçenekleri bile kullanabilirsiniz: hizmetin dış dünyaya tek bağlantısı sistemd'den aldığı ağ soketi olacak, başka hiçbir şeye bağlanamayacak. Yalnızca bazı bağlantı noktalarını dinleyen ve diğer sunuculara bağlanması gerekmeyen basit bir sunucuysa, bu yararlı olabilir. (Dosya sistemi ile ilgili seçenekler de RootDirectoryeski olabilir, bence, belki de artık gerekli tüm ikili ve kütüphanelerle yeni bir kök dizin oluşturmaya gerek yok.)

Daha yeni systemd sürümleri (v232'den beri) de desteklenir DynamicUser=yes; burada systemd, hizmet kullanıcısını otomatik olarak yalnızca hizmetin çalışma zamanı için tahsis eder. Bu araçlar size hizmet için kalıcı bir kullanıcı kaydı var ve onun dışında herhangi bir dosya sistemi konumlara yazmaz uzun hizmetinin yanı cezası çalışır yok StateDirectory, LogsDirectoryve CacheDirectory(aynı zamanda birim dosyasında ilan edebilir ki - man 5 systemd.exectekrar bakın - ve daha sonra hangi sistem yöneticisini yönetecek, bunları dinamik kullanıcıya doğru bir şekilde atamaya dikkat edin).

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.