Do Świata Web3 dołączyli kolejni goście - audytorzy bezpieczeństwa smart contracts z firmy Composable Security 🇵🇱⛓️ Przeprowadzili audyty dla projektów takich jak Enjin, FujiDAO czy Tellor. Stworzyli również Smart Contract Security Verification Standard, a założycielami są Damian Rusinek oraz Paweł Kuryłowicz.
Jeżeli tworzysz projek oparty o smart contracts to zapraszamy do kontaktu 👇
Dzisiaj jednak oddali pióro do jednego z audytorów, Jakuba Zmysłowskiego, który w niezwykle wnikliwy sposób przedstawi Wam jak audyty smart contracts wyglądają w praktyce.
Inspirującej lektury! 👾
Tyle się słyszy o tych wszystkich zhakowanych projektach… Wg. slowmist, na dzień dzisiejszy [12.01.2022] w świecie krypto skradziono do tej pory prawie 29 miliardów dolarów w wyniku ponad 900 hacków! Jednak nie wszystkie hacki kończą się kradzieżą. Oprócz tak zwanych czarnych kapeluszy, czyli cyberprzestępców nastawionych na osiąganie korzyści finansowych na skutek ataków hakerskich, są jeszcze białe.
Nazywam się Jakub Zmysłowski i pracuję w firmie Composable Security na stanowisku smart contract auditor. W naszej pracy wspieramy projekty w zabezpieczaniu, pomagając im zminimalizować ryzyko zasilenia tej i tak ogromnej kwoty strat.
Pozwól, że przybliżę Ci najistotniejsze elementy dbania o bezpieczeństwo na podstawie doświadczenia zbieranego w wieloletniej współpracy z projektami opartymi o technologię blockchain z całego świata.
Z poniższego wpisu dowiesz się co kryje się pod skrótem SDLC, na czym polega modelowanie zagrożeń oraz jak wygląda audyt bezpieczeństwa inteligentnych kontraktów.
Agenda na dziś:
Po co nam audyty bezpieczeństwa?
Zacznijmy od SLDC
Jakie są etapy SDLC podczas tworzenia projektu?
Audyt smart contractów
Jak wygląda audyt bezpieczeństwa w praktyce?
Podsumowanie
Po co nam audyty bezpieczeństwa?
Czy dzięki współpracy z jakimkolwiek audytorem istnieje 100-procentowa gwarancja, że Twój projekt będzie bezpieczny i nikt nie znajdzie sposobu na to by skrzywdzić Twoich użytkowników?
Niestety nie.
Portal rekt.news na bieżąco przedstawia krótkie analizy (tzw. postmortem) dokonanych ataków. Jak widzimy na tablicy leaderboard, mimo że sporo z tych projektów nie było audytowanych, to niemal równie duża ilość dokonała audytu. Czasem nawet więcej niż raz i to nie przez małe nieznane firmy, a dużych liderów rynku takich jak Peckshield, Certik czy Quantstamp.
Czy więc w ogóle warto próbować dbać o bezpieczeństwo skoro i tak możemy paść ofiarą hacku? Zdecydowanie tak!
Kluczowe jest zrozumienie faktu iż dbanie o bezpieczeństwo to minimalizacja ryzyka, a nie jego eliminacja.
Zapewnienie bezpieczeństwa to wieloetapowy proces, który obejmuje następujące działania:
Modelowanie zagrożeń w celu wczesnej ich identyfikacji
Edukacja i warsztaty zwiększające świadomość bezpieczeństwa i zagrożeń wśród developerów.
Regularne audyty przeprowadzane przez profesjonalne firmy.
Monitorowanie kontraktów po deployu (wdrożeniu kontraktów).
Uczestniczenie w programach bug bounty (“publiczne” audyty realizowane poprzez portale takiej jak Immunefi czy Code4Arena).
i wiele więcej!
Cyfrowe aktywa przyciągają coraz więcej uwagi i ich wartość wzrasta (no może nie w ostatnich dniach :D) co oczywiście nie mogło umknąć uwadze atakujących. Jak ktoś kiedyś zauważył:
„Możesz okraść bank lub firmę krypto. Oba mają miliony, ale w przeciwieństwie do tradycyjnych banków, firmy krypto to w dużej części startupy zatrudniające 20 osób”.
Będąc tak mocno wystawionym na atak, na co dodatkowo wpływa transparentność i możliwość wglądu w kod inteligentnych kontraktów, dbanie o bezpieczeństwo nie jest kwestią wyboru - to obowiązek.
Na koniec jeszcze mały disclaimer - pojęcie “audyt” oznacza sprawdzenie podmiotu zgodnie z z określonymi standardami, wzorcami, listami itp. Większość firm nie używa jednak żadnego standardu, więc usługa którą wykonują to tak naprawdę “security review” czy też testy bezpieczeństwa. Zgodnie z powielanym błędem pozwolę sobie w tym wpisie stosować te pojęcia wymiennie na potrzeby pozycjonowania i byście nie byli nimi zaskoczeni :-).
Dołącz do ponad 600 pasjonatów technologii Web 3.0:
Zacznijmy od SDLC
Cykl życia oprogramowania (ang. Software Development Life Cycle – SDLC) to schemat stosowany podczas tworzenia oprogramowania, więc również i smart contractów. Jego celem jest zapewnienie, aby oprogramowanie zostało właściwie zaprojektowane i w sposób bezpieczny spełniało potrzeby użytkowników.
Zrozumienie poszczególnych etapów tego procesu pozwoli Ci na szersze spojrzenie skąd i dlaczego powstają błędy bezpieczeństwa, oraz jakie kroki można podjąć aby ograniczyć ryzyko ich powstawania.
Jakie są etapy SDLC podczas tworzenia projektu?
Analiza
Na tym etapie określa się cele i wymagania systemu, a także harmonogram i budżet projektu. Z perspektywy bezpieczeństwa działanie jakie należy tu podjąć nazywane jest modelowaniem zagrożeń. Polega ono na analizie bieżącego ryzyka, potencjalnych konsekwencji i środków zaradczych, aby uniknąć zidentyfikowanych zagrożeń. Modelowanie zagrożeń przeprowadza każdy z nas. By Ci to udowodnić, podam prosty przykład. Czy założysz koszulkę Widzewa Łódź spacerując po dzielnicach ŁKSu zaraz po meczu derbowym? Oczywiście, że nie! Nie potrzeba do tego skomplikowanych diagramów i schematów. Każdy z nas wie, że mogłoby się to źle skończyć. W tak prostym przypadku wystarczy zdrowy rozsądek i chwila zastanowienia.
Stworzenie modelu zagrożeń na wczesnym etapie SDLC pomaga zrozumieć co będzie budowane i zweryfikować w jaki sposób zrobić to dobrze - koncentrując się na kwestiach bezpieczeństwa. Aby odpowiedzieć na pytanie „Czy to oprogramowanie jest bezpieczne?” lub „Jakie mechanizmy bezpieczeństwa powinniśmy zastosować?” konieczna jest identyfikacja potencjalnych zagrożeń.
Wdrożenie procesów bezpieczeństwa na wczesnym etapie powstawania projektu pozwala nie tylko na zwiększenie bezpieczeństwa, ale także na optymalizację kosztów (w tym tych, które projekt może ponieść w wyniku hacku). Nie raz i nie dwa nasi nowi klienci po pierwszej solidnej rundzie testów musieli przekładać datę startu czy nawet zaprojektować na nowo architekturę swojego projektu. Niestety, nie wszystkie podatności są łatwe i szybkie do usunięcia. Część jest trudna i czasochłonna, dlatego najlepiej po prostu zapobiegać ich powstawaniu.
Przykładowy model zagrożeń dla zdecentralizowanej giełdy może wyglądać tak:
Jeśli chcesz dowiedzieć się więcej o modelowaniu zagrożeń, możesz przeczytać wpis który podlinkowuję poniżej:
Projektowanie
Podczas tego etapu opracowywane są szczegółowe specyfikacje techniczne, zgodnie z zasadą minimalnych uprawnień (ang. principle of least privilege). Według tej zasady, użytkownicy powinni mieć tylko te uprawnienia, które są niezbędne do wykonywania przeznaczonych dla nich operacji. Ważne jest również zaprojektowanie właściwej kontroli dostępu.
Każdy z nas spotyka się z mechanizmami kontroli dostępu w życiu codziennym. Świetnym przykładem na to jest to, jak będąc na koncercie Philla Collinsa mijałem bramki zabezpieczające przed wejściem osób nieupoważnionych na backstage. Ochroniarze weryfikowali tożsamość osób wchodzących na teren imprezy oraz eliminowali potencjalne zagrożenia jak np. wniesienie niebezpiecznych przedmiotów czy też własnego alkoholu przeszukując nasze rzeczy. VIPom natomiast bardzo szybko wydawano identyfikatory z imieniem i nazwiskiem, które dawały specjalne uprawnienia i dużo większą swobodę
Kontrola dostępu w smart contractach działa podobnie. Możemy wyróżnić role takie jak Użytkownik, Właściciel czy Administrator i przypisać do nich w kodzie kontraktu odpowiednie uprawnienia. Taki prosty zabieg pozwala na ograniczenie dostępu do potencjalnie niebezpiecznych funkcji i świadome zarządzanie tym “do czego?” i “kto?” powinien mieć dostęp. Popularnymi funkcjami do których praktycznie zawsze stosuje się kontrolę dostępu są te odpowiadające za np. zmianę governance czy wstrzymanie kontraktu.
Implementacja (tworzenie kodu)
W fazie implementacji realizowane są prace związane z tworzeniem kodu smart contractów. Należy tu oczywiście pamiętać o najlepszych praktykach programowania! Spośród popularnych podatności, które mogą powstać ze względu na nieznajomość tych praktyk, możemy wskazać np. re-entrancy, denial of service, niezainicjalizowane kontrakty czy brak kontroli dostępu. Regularne szkolenia i wspólne omawianie raportów z audytów pomogą w zapewnieniu jakości implementowanego kodu.
Testowanie
W tym etapie system jest testowany pod kątem poprawności działania oraz zgodności z wymaganiami. Pokrycie kodu testami to proces, w którym tworzy się zestawy instrukcji, które sprawdzają, czy kod kontraktu działa zgodnie z zaprojektowanymi oczekiwaniami. Celem tych testów jest zapewnienie, że kod będzie działać poprawnie niezależnie od tego, jakie dane wejściowe zostaną mu przekazane.
Oprócz testów funkcjonalnych, warto również na tym etapie zweryfikować kod pod kątem bezpieczeństwa. Można w tym celu skorzystać z dobrych i sprawdzonych w boju rozwiązań. Narzędzia takie jak Slither pozwolą na wyłapanie potencjalnych “low-hanging fruits” Pamiętajmy, bezpieczeństwo to nic innego jak dokładanie kolejnych i kolejnych warstw, gdzie każda z nich jest istotna. Różne metody zabezpieczeń tworzą pełny, kompleksowy system bezpieczeństwa, który ma na celu zniechęcić atakującego do podjęcia próby złamania zabezpieczeń oraz możliwie szybko wykryć jego działanie i na nie zareagować.
Smart contracty są więc jak…
OGRY!
Naszym celem jest ochrona przed różnymi rodzajami zagrożeń poprzez zastosowanie wielu różnych narzędzi i technik. Slither nie jest jednak jedynym narzędziem i z pewnością nie nadaje się do wszystkiego (choć najprawdopodobniej jest to najpopularniejszy “security tool” wśród developerów). Jego głównym zastosowaniem jest wykrywanie znanych podatności. W celu tworzenia
testów automatycznych - kodu, który automatycznie sprawdzi poprawność działania kontraktów i zidentyfikuje potencjalne błędy,
fuzzingu - generowania mnóstwa nietypowych, nieprawidłowych i losowych danych wejściowych celem wykrycia nietypowych zachowań
imitowania środowiska produkcyjnego - tak, aby w czasie testów jak najdokładniej odwzorować “realne” środowisko życia naszych kontraktów
należy skorzystać z innych narzędzi takich jak truffle, hardhat, brownie, echidna czy foundry.
Warto zadbać o to, aby testy przeprowadzanie były w środowisku możliwie jak najlepiej odwzorowującym to docelowe. Z pomocą w tym aspekcie przychodzą sieci testowe takie jak Goerli czy Sepolia. Developerzy za darmo mogą tam skorzystać z testowych tokenów i wykonać swoje testy w środowisku w którym żyją inne projekty.
Do początkowych iteracji testów w trakcie developmentu warto jednak stworzyć “mocki” (atrapy imitujące prawdziwe kontrakty) pozwalające na szybką symulację skomplikowanych integracji.
Wdrożenie
Protokół zostaje wysłany na blockchain, czyli na środowisko produkcyjne Web3. Podczas tego etapu ważne jest właściwe zainicjalizowanie wszystkich zmiennych. W przypadku kontraktów “upgradable” (wzorzec zgodnie z którym logika przechowywana jest w odrębnym kontrakcie, który może zostać zastąpiony innym) należy upewnić się, że funkcja inicjalizująca może zostać uruchomiona tylko raz. Jest to typowa podatność bezpieczeństwa, którą niestety występuje nadal. Jeśli chcesz dowiedzieć się o niej więcej, polecam świetny artykuł Adriana Hetmana.
Utrzymanie
Podczas tego etapu protokół jest monitorowany i aktualizowany celem ulepszania jego sprawności i bezpieczeństwa.
Audyt smart contractów
Przez wiele osób za kluczowy element dbania o bezpieczeństwo projektu uważany jest audyt. Osobiście uważam, że jest to tylko jeden z wielu elementów - niemniej bardzo istotny. Podczas testów bezpieczeństwa audytorzy sprawdzają kontrakty pod kątem różnych zagrożeń. Szukamy znanych podatności, błędów powtarzających się na świecie i wśród naszych klientów, a także weryfikujemy specjalnie opracowane i spersonalizowane scenariusze ataku. Celem takich testów jest zapewnienie, że kontrakty te są bezpieczne i wydajne. Chcemy maksymalnie zmniejszyć ryzyko wystąpienia błędów pozwalających na przeprowadzenie ataku.
Po zidentyfikowaniu luk, przedstawiamy proponowane sposoby usunięcia wykrytych podatności. Nie zawsze jest to proste, ale zawsze staramy się być pod ręką i wspierać zespoły w poszukiwaniu rozwiązań. To zawsze dobrze zainwestowany czas w trakcie którego dużo się uczymy. Bez dwóch zdań, audyty bezpieczeństwa są ważnym elementem procesu tworzenia i wdrażania inteligentnych kontraktów.
Czy audyt to odpowiedź na wszystkie bolączki i panaceum w kontekście bezpieczeństwa? Nie. To usługa z której należy skorzystać na bardzo konkretnych etapach:
Przed wdrożeniem - to moment w którym warto wykonać test całego protokołu oraz integracji z wszystkimi komponentami zewnętrznymi. Jest to ostatni moment na eliminację błędu zanim kontrakty zostaną już na zawsze zapisane w sieci blockchain,
Po wprowadzeniu istotnych zmian - każda zmiana w kodzie, nie będąca komentarzem czy poprawką czytelności kodu, może mieć wpływ na bezpieczeństwo projektu. Z pozoru niewielka ilość kodu potrafi być brakującym elementem do spełnienia scenariuszu ataku narażającego klienta i jego użytkowników na niebezpieczeństwo. Na tym etapie testy skupiają się na komponencie w którym zaszła zmiana oraz wszystkich innych komponentach na które mogła mieć wpływ. Zdecydowanie warto w takim przypadku zwrócić się do firmy, która zna już kod projektu i nie będzie musiała zapoznać się z całością w celu zweryfikowania drobnej zmiany,
Cross-check - czyli ponowny audyt z wykorzystaniem innej grupy specjalistów. Podejście szczególnie polecane projektom obarczonym dużym ryzykiem jak np. protokoły lendingowe. Pozwala na zastosowanie kilku różnych metodyk pracy audytorów i eksperymentowanie z indywidualnym podejściem różnych firm.
Przeprowadzając audyt inteligentnych kontraktów, organizacje mogą poprawić bezpieczeństwo i wiarygodność swoich inteligentnych kontraktów, upewniając się, że działają one zgodnie z przeznaczeniem i nie są podatne na ataki.
Jak wygląda audyt bezpieczeństwa w praktyce?
Audyt smart kontraktu podobny jest do tradycyjnego audytu finansowego, z tą różnicą, że zamiast sprawdzać księgi, audytorzy sprawdzają kod. Oczywiście, każda firma w inny sposób przeprowadza taki audyt. Opowiem Wam o naszym podejściu w Composable Security wypracowanym na podstawie długiej współpracy z wieloma projektami.
Przygotowanie protokołu do audytu
Audyt bezpieczeństwa sprowadza się do dołożenia wszelkich starań, aby znaleźć wszystkie błędy bezpieczeństwa w protokole, w ograniczonym czasie. Stąd, ważna jest równowaga między kosztami po stronie klienta a jak najlepszym wykonaniem pracy testerów. Jako audytorzy musimy oszacować ile czasu zajmie nam dokładne zrozumienie projektu i zweryfikowanie potencjalnych zagrożeń. Czytelny
i uporządkowany kod jest łatwiejszy do zrozumienia, więc również i oszacowania czasu potrzebnego na wykonanie testów. Ciężko jest jednak podać uśredniony czas trwania - wszystko zależy od długości kodu (dla Ethereum tzw. SLOC - solidity line of code) i jego skomplikowania. Projekty, które najczęściej realizujemy zajmują między 1, a 4 tygodnie pracy specjalistów.
Pamiętajmy jednak, że wszystko jest względne i każda firma inaczej oszacuje długość trwania testów :)
Pomocnym źródłem informacji o projekcie jest dokumentacja techniczna. Warto więc przed audytem zaktualizować whitepaper i przygotować diagramy opisujące przepływ informacji.
Dobre przygotowanie do testów znacząco może obniżyć jego koszta.
Zrozumienie projektu
Dokładne zrozumienie, jak projekt ma działać jest kluczowe dla właściwej realizacji audytu. W czasie tego etapu trzeba odpowiedzieć na pytania jaki jest model biznesowy oraz jakie elementy, komponenty i założenia są kluczowe dla prawidłowego działania protokołu
Dzięki temu możemy udzielać znacznie lepszych porad, rekomendacji i lepiej odpowiadać potrzebom projektu.
Modelowanie zagrożeń
Bazując na swojej wiedzy i doświadczeniu, testerzy skupiają się podczas audytu na najważniejszych zagrożeniach. Poza standardowymi kwestiami bezpieczeństwa (odpowiednio dla każdego rodzaju protokołu) testy powinny zostać rozszerzone o scenariusze potencjalnych ataków zaprojektowane specjalnie dla audytowanego projektu.
Ważne jest, aby dobrać realne zagrożenia - również takie które w przeszłości kończyły się hackiem.
Testy automatyczne
Testowanie automatyczne to proces wykorzystujący specjalne narzędzia do automatyzacji przeprowadzenia testów. W przypadku audytów inteligentnych kontraktów może to obejmować m.in. sprawdzenie poprawności działania logiki kontraktu, sprawdzenie zgodności z określonymi zasadami (jak standardy ERC), czy też sprawdzenie przepływu środków finansowych w ramach kontraktu. Narzędzia te pozwalają szybciej przekazać informacje o ogólnym stanie kodu i standardowych lukach w zabezpieczeniach. Jedną z metod testowania jest także fuzzing. Metoda ta polega na wysyłaniu do systemu losowych danych wejściowych w celu wykrycia potencjalnych błędów i luk w zabezpieczeniach.
Narzędzia do automatyzacji testów pozwalają na efektywniejsze wykorzystanie czasu w projekcie.
Weryfikacja manualna
Kod projektu jest “ręcznie” sprawdzany przez audytorów. Jest to najbardziej czasochłonna faza audytu, podczas której przechodzą oni linijka po linijce, aby zweryfikować obecność luk w zabezpieczeniach, w sposobie integracji z zewnętrznymi komponentami oraz logice biznesowej.
Weryfikacja scenariuszy dostosowanych do projektu pozwala na zidentyfikowanie potencjalnych błędów.
Dostarczenie raportu
Dostarczony raport jest źródłem informacji dla zespołu projektowego. Podatności, rekomendacje i zalecenia powinny być opisane w zrozumiały dla nich sposób. Raport wyróżnia m.in. sekcje podsumowania wykonawczego, podatności na zagrożenia oraz rekomendacji.
Czas na wdrożenie poprawek
Po otrzymaniu raportu zespół projektowy ma czas na wdrożenie zaleceń. Będąc cały czas w kontakcie z audytorami, mogą dopytywać się o kwestie dotyczące raportu.
Wszystkie zalecenia powinny zostać wdrożone.
Retest
Po wprowadzeniu poprawek przeprowadzamy dodatkowo jednorazową weryfikację, aby upewnić się, że zalecenia zostały wprowadzone we właściwy sposób, a znalezione podatności zostały wyeliminowane.
Podsumowanie
Jednym z największych powodów, dla którego zdecentralizowane aplikacje stają się popularne, jest to, że zmniejszają ryzyko oszustwa, usuwając błąd ludzki z równania. Korzyść ta wiąże się jednak z zagrożeniem: wadliwy kod może spowodować, że projekt nie będzie działał tak jak powinien, a nawet stanie się podatny na ataki.
Drogi Czytelniku, mam nadzieję, że przybliżyłem Ci kwestię bezpieczeństwa w smart contractach. Jeśli chciałbyś wiedzieć więcej lub sięgnąć po pomoc specjalisty - napisz do nas, a zrobimy co w naszej mocy by Ci pomóc!