Czyli jakie błędy deweloperów obniżają bezpieczeństwo ich oprogramowania na Linuksie?
Menedżerowi pakietów deweloper musi pomóc
Jednym z najważniejszych zadań menedżera pakietów w danej dystrybucji Linuksa (np. apt w Debianie) jest zapewnienie, że oprogramowanie dostarczane użytkownikom jest wolne od luk w zabezpieczeniach. Podczas gdy znalezienie i naprawienie podatnego kodu jest zwykle uważane za odpowiedzialność deweloperów, osoba tworząca paczkę musi zapewnić, że wszystkie te poprawki jak najszybciej dotrą do użytkowników końcowych. Dzięki centralnemu zarządzaniu pakietami dystrybucje Linuksa znacznie usprawniły wdrażanie poprawek bezpieczeństwa. Czasami wystarczy załatać pojedynczą bibliotekę współdzieloną za pośrednictwem automatycznego systemu aktualizacji dystrybucji.
Ale działa to tylko wtedy, gdy dany pakiet faktycznie przestrzega dobrych praktyk bezpieczeństwa. Go, Rust i nawet w pewnym zakresie Python to tylko kilka przykładów języków programowania, które zintegrowały złe praktyki bezpieczeństwa z samą strukturą swojego istnienia i odtworzyły stare problemy w zupełnie nowy sposób.
Linkowanie statyczne
Jedną z praktyk przeszkadzających w zarządzaniu bezpieczeństwem pakietów jest osadzanie zależności programu bezpośrednio w obrazie tego programu. Przeciwieństwem takiego działania jest dynamiczne linkowanie, które utrzymuje zależne biblioteki w osobnych plikach, które są ładowane podczas uruchamiania programu (lub w czasie wykonywania).
Dlaczego linkowanie statyczne jest złe? Podstawowym problemem jest to, że skoro biblioteki stają się integralną częścią programu, nie można ich łatwo zastąpić inną wersją. Jeśli okaże się, że jedna z bibliotek jest podatna na atak, musisz ponownie połączyć cały program z nową wersją. Oznacza to również, że musisz mieć system, który śledzi, jakie wersje bibliotek są używane w poszczególnych programach.
Skrajnym przypadkiem linkowania statycznego jest dystrybucja zastrzeżonego oprogramowania, które jest statycznie powiązane z jego zależnościami. Ma to na celu przede wszystkim zapewnienie łatwego uruchamiania oprogramowania w różnych systemach bez konieczności ręcznego instalowania jego zależności przez użytkownika. Statyczne łączenie było również używane w przeszłości w programach systemowych, które miały działać, nawet jeśli ich biblioteki zależne uległy uszkodzeniu.
Go czy Rust postrzegają statyczne łączenie jako fundementy tych języków i wielokrotnie publicznie stwierdzano, że nie przejdą one na dynamiczne łączenie zależności.
Przygwożdżone zależności
Chociaż linkowanie statyczne jest złe, przynajmniej dość jasne jest tutaj jak automatycznie aktualizować takie programy. Tymczasem „przypinane” czy „przygwożdżone” zależności (pinned) są jeszcze gorsze - oznaczają konieczność zainstalowania określonej wersji zależności programu. Czyli przynajmniej niektórzy użytkownicy danego pakietu nie będą mogli automatycznie aktualizować zależności do nowszych wersji. Jeśli dla zależności zostanie wydana poprawka lub - co ważniejsze - poprawka luki w zabezpieczeniach, użytkownicy nie otrzymają jej.
Sprawdź oferty pracy na TeamQuest
Dlaczego ludzie przypinają zależności? Głównym powodem jest to, że nie chcą, aby aktualizacje zależności nagle zepsuły ich pakiety dla użytkowników końcowych. Przypinanie pogarsza sytuację, ponieważ zamiata problem pod dywan i aktywnie zachęca ludzi do tworzenia kodu w oparciu o określone wersje ich zależności.
Spuchnięcie programu może oznaczać chorobę
Obie techniki to złe praktyki, które mają generują zapotrzebowanie na czas i wysiłek potrzebny do wyeliminowania luk w systemach produkcyjnych. Mogą sprawić, że zamiast zastąpić podatną bibliotekę w ciągu kilku minut zaistnieje konieczność poświęcenia znacznych zasobów na zlokalizowanie wielu kopii podatnej biblioteki, zainstalowanie poprawek i odbudowanie całego oprogramowania.
Główne dystrybucje Linuksa od bardzo dawna stosowały zasady przeciwdziałające tym praktykom ale coraz bardziej przypomina to syzyfowe zadanie. Zamiast pakować zależności i pisać programy tak aby korzystały one z najnowszych wersji programów, po prostu robimy z nich duże „bloby”.