Zbudujmy ścianę, czyli bezpieczeństwo naszych systemów
Cześć!
Do końca meczu NBA zostało 0.3 sekundy. Detroit Pistons prowadzili jednym punktem z San Antonio Spurs. Piłka była w rękach graczy z San Antonio. Jak zwykle w koszykówce, ostatnie sekundy ciągną się przerywane przerwami dla trenerów do ustawienia zagrywki. Stan Van Gundy trener Pistons miał tylko jedną receptę:
“We just form a fucking wall!!!”
Zobacz to z resztą tutaj:
Na północ od Winterfell też postawiono ścianę. Nawet większą niż taką jaką postawili Pistons. Dodatkowo magiczną, taką którą można przejść tylko górą. Co samo w sobie było zadaniem prawie niewykonalnym.
Ściana ta miała tylko jedną wadę. Była zabezpieczona z jednej strony - z tej, z której spodziewano się ataków. Jeśli ktoś przeszedł nad ścianą, albo zaatakował ją od drugiej strony to… Jesień średniowiecza. A w zasadzie zima.
Gdy zaczynałem swoją karierę szczytem wyrafinowania była ochrona przed SQL injection czy cross site scripting. Admini instalowali MSSQL na serwerach z wyłączonym Internetem, bo domyślnie otwarty na świat był potencjalnym źródłem ataku. Konfiguracja firewalla to było wyzwanie.
Dzisiaj mamy lżej. Używając chmury wiele rzeczy mamy zapewnione. Dostawcy chronią nas przed podstawowymi włamaniami. Blokują atak DDos i wiele innych ataków, o których istnieniu nawet nie wiemy. Stawiają nam ścianę, którą ciężko jest przebić.
Jakiś czas temu stwierdziłem jednak, że ściana, która jest stawiana przez dostawców chmurowych przypomina trochę tę z Gry o Tron. Nie z ich winy - z naszej.
Te bezpieczeństwo chmur oraz skupienie się na technicznym aspekcie bezpieczeństwa wprawia nas zbyt często w błogi nastrój. Mamy https, OAuth, VPNy w środku i to jest super, tylko często sprawia, że uważamy, że to wystarczy.
Sam się spotkałem w swoich projektach, że przy definiowaniu serwisów i ich zależności (np. serwis do bazy danych, storage na pliki, itd.) z lenistwa programistycznego dostawał zawsze gwiazdeczkę. Czyli zamiast sprecyzować, że nasz serwsi ma dostęp tylko do takiego schematu bazy, albo tylko do takich plików, to programista po prostu dawał gwiazdeczkę i serwis dostawał dostęp potencjalnie do wszystkiego. Odpowiedź jest, że “przecież to tylko wewnętrzna konfiguracja, API jest zabezpieczone”.
Inny przypadek, bardziej drastyczny. Serwis uwierzytelniany przy pomocy certyfikatów. Para certyfikatów współdzielona przez wszystkich klientów. Zapytanie podpisywane w kodzie aplikacji, a certyfikaty wkompilowane w kod. “Przecież klient by musiał sobie to zdekompilować”. No tylko, że dekompilacja jak się wie, że można to znaleźć to zaledwie 5 minut roboty.
Inna sprawa to klucze aplikacji. Często używane są do integracji. W przeciwieństwie do haseł, nie są rotorowane. Zwykle mają długi cykl życia i ktoś mając do nich dostęp może wywoływac nasze usługi.
Kevin Mitnick zwykł mówić, że łamał ludzi, nie hasła. W obecnych czasach tym bardziej najsłabszym punktem bezpieczeństwa naszych systemów jesteśmy my. To my wpisujemy hasła typu imię córki, qwerty itd. To my przyklejamy sticky notesy z hasłami czy tez zapisujemy hasła w plikach tekstowych.
Wytwarzając aplikacje zwykle musimy iść na kompromisy jakościowe. “No OK, w tej sytuacji się wywali, ale to przeżyjemy”. Bezpieczeńśtwo nie jest miejscem gdzie możemy machnąć ręką. Konsekwencje błędu są dużo poważniejsze. Tutaj z założenia powinniśmy coś blokować, a udostępniać precyzyjnie to na co pozwalamy.
Hackerzy (sami, lub poprzez boty) zwykle szukają luk bezpieczeństwa. Gdy takie znajdą, to drążą dalej. Przebiją się przez jedną ścianę, i szukają luki w kolejnej ścianie. Co gdy mamy tylko jedną ścianę?
Wtedy np. ktoś kto ma hasło i dostęp do endpointu jeśli damy gwiazdeczkę to w teorii może zrobić wszystko z naszymi danymi. Oczywiście możemy powiedzieć, że “tylko tyle ile kod pozwoli”. No ale jeśli kod pozwoli na dużo bo sam ma luki? Nie tylko w naszej napisanej logice, ale co jeśli biblioteki, które używamy mają luki typu “zero day”? Zobacz np. co można było zrobić podając ciąg binarny w Javie: https://github.com/frohoff/ysoserial. To pomyśl co można zrobić z tą inną Javą - np. https://medium.com/intrinsic/common-node-js-attack-vectors-the-dangers-of-malicious-modules-863ae949e7e8.
Co może zrobić sprytny nudzący się klient programisty ze wkompilowanym certyfikatem do Twojego narzędzia?
Mało? To zobacz np. testowych użytkowników. Każdy praktycznie ma takieg “qauser” z hasłem “qwerty12345”. Czasem nawet może i lepszym hasłem, ale ciągle takim co wszyscy je znają. Dla zasady nie zmienia mu się hasła, bo przecież to niewygodne. Co teraz jeśli, któryś z pracowników jest sprytny i ma nieczyste intencje? Albo został zwolniony i jest rozczarowany i chce się zemścić? Co jeśli się okaże, że ten użytkownik jest też użytkownikiem w chmurze (np. Azure AD) i jeszcze inne dostępy wewnątrz systemu są mu bezpośrednio przypisane? Co gorsza, jeśli jest on adminem? Często konfigurując takich użytkowników nie zdajemy sobie sprawę jak dużo można takim użytkownikiem zrobić.
Ufasz swoim współpracownikom? Świetnie! A co jeśli do użytkownika testowego ma dostęp klient? Albo wygenerowaliśmy mu access key żyjący rok? Za klienta też dasz sobie rękę uciąć? Tak? OK. A za bezpieczeństwo u niego i, że nikt mu tych danych nie przechwyci?
W dzisiejszych czasach zaawansowane metody bezpieczeńśtwa są na wyciągnięcie ręki. Możemy nawet każdemu pracownikowi dać dostęp do menadżera haseł (np. https://bitwarden.com/, https://1password.com). Możemy tam ustawić 2 factor authentication, możemy rotować hasła. Możemy momentalnie odciąć dostęp. To samo z bazami, możemy robić rotacje haseł przy pomocy narzędzi typu Vault (https://www.vaultproject.io/). Każdy dostawca chmury ma to wbudowane, a stopień skomplikowania konfiguracji nawet dla rozwiązań on-premise wcale nie jest duży. Wszystko można.
To co jednak jest najtrudniejsze to myślenie i wyczulenie na to co robimy i czy chcemy się troszczyć o bezpieczeńśtwo. Niektóre rzeczy można załatwić brakiem olewactwa.
Dlatego zanim kolejny raz damy gwiazdeczkę w dostępie do zasobów, zanim stwierdzimy, że “przecież nikt na to nie wpadnie” zastanówmy się czy to jest ta ściana, którą chcemy zbudować.
Pozdrawiam Oskar
p.s. w zeszłym tygodniu napisałem na blogu o rozproszonych procesach w praktyce: https://event-driven.io/en/saga_process_manager_distributed_transactions/. Uważam nieskromnie, że całkiem nieźle ten wpis wyszedł. Zachęcam do lektury! p.s.2 Dzisiaj też wyszło dziesiąte ArchitectureWeekly https://github.com/oskardudycz/ArchitectureWeekly#15th-february-2021. Podziel się ze znajomymi jeśli podobają Ci się te linki. Będzie też mi miło jak ich zaprosisz do mojego newslettera.