Bezpieczeństwo inteligentnych kontraktów
Strona ostatnio zaktualizowana: 14 lutego 2026
Inteligentne kontrakty są ekstremalnie elastyczne oraz zdolne kontrolować duże ilości wartości oraz danych oraz dane stosując niezmienną logikę opartą na kodzie wdrożonym na blockchainie. Powstał dzięki temu tętniący życiem ekosystem niewymagających zaufania i zdecentralizowanych aplikacji, które zapewniają szereg przewag wobec przestarzałych systemów. Stwarzają one również okazje dla napastników szukających zysku poprzez wykorzystanie słabych punktów inteligentnych kontraktów.
Publiczne blockchainy takie jak Ethereum, jeszcze bardziej komplikują zagadnienie zabezpieczeń inteligentnych kontraktów. Kod wdrożonego kontraktu zazwyczaj nie może zostać zmieniony w celu załatania luk w zabezpieczeniach, podczas gdy aktywa skradzione z inteligentnych kontraktów są niezwykle trudne do wyśledzenia i w większości nie do odzyskania ze względu na niezmienność.
Źródła podają różne kwoty, ale można oszacować, że suma środków skradzionych lub straconych w wyniku defektów zabezpieczeń w inteligentnych kontraktach przekracza 1 miliard dolarów. Obejmuje to głośne incydenty, takie jak atak na DAOopens in a new tab (skradziono 3,6 mln ETH, wartych dziś ponad 1 mld USD), atak na portfel wielopodpisowy Parityopens in a new tab (hakerzy ukradli 30 mln USD) oraz problem z zamrożonym portfelem Parityopens in a new tab (ponad 300 mln USD w ETH zablokowane na zawsze).
Wspomniane wcześniej problemy stwarzają programistom konieczność poświęcania uwagi i środków na tworzenie zabezpieczonych, solidnych i odpornych inteligentnych kontraktów. Bezpieczeństwo inteligentnych kontraktów jest poważną sprawą, o której powinien uczyć się każdy programista. W tym przewodniku omówione zostaną zagadnienia związane z bezpieczeństwem skierowane dla programistów Ethereum oraz zasoby ulepszania zabezpieczeń inteligentnych kontraktów.
Wymagania wstępne
Przed zajęciem się kwestiami bezpieczeństwa upewnij się, że znasz podstawy tworzenia inteligentnych kontraktów.
Wytyczne dotyczące budowania bezpiecznych inteligentnych kontraktów Ethereum
1. Zaprojektuj odpowiednie mechanizmy kontroli dostępu
W inteligentnych kontraktach funkcje oznaczone jako public lub external mogą być wywoływane przez dowolne konta zewnętrzne (EOA) lub konta kontraktowe. Określenie publicznej widoczności funkcji jest konieczne, jeśli chcesz, aby inni mogli wchodzić w interakcje z twoim kontraktem. Funkcje oznaczone jako private mogą być jednak wywoływane tylko przez funkcje w ramach danego inteligentnego kontraktu, a nie przez konta zewnętrzne. Udzielanie każdemu użytkownikowi sieci dostępu do funkcji kontraktu może stwarzać problemy, szczególnie jeśli oznacza to, że każdy może przeprowadzać wrażliwe czynności (np. mintowanie nowych tokenów).
Aby uniemożliwić nieautoryzowane użycie funkcji inteligentnego kontraktu, niezbędna jest implementacja zabezpieczeń kontroli dostępu. Mechanizmy kontroli dostępu ograniczają możliwość użycia określonych funkcji inteligentnego kontraktu podmiotom innym niż aprobowane, czyli te konta, które odpowiedzialne są za zarządzanie kontraktem. Wzorce Ownable oraz kontroli opartej na rolach to dwa przydatne schematy implementacji kontroli dostępu w inteligentnych kontraktach:
Wzorzec Ownable
We wzorcu własności, adres oznaczony jest jako "właściciel" kontraktu podczas procesu tworzenia kontraktu. Funkcje chronione mają przypisany modyfikator OnlyOwner, który zapewnia, że kontrakt uwierzytelnia tożsamość adresu wywołującego przed wykonaniem funkcji. Wywołania funkcji objętych ochroną pochodzące od innych adresów oprócz właściciela kontraktu są zawsze pomijane, co uniemożliwia niechciany dostęp.
Kontrola dostępu oparta na rolach
Zarejestrowanie pojedynczego adresu jako Owner w inteligentnym kontrakcie wprowadza ryzyko centralizacji i stanowi pojedynczy punkt awarii. Jeśli klucze dostępu konta właściciela wpadną w niepowołane ręce, napastnicy mogą zaatakować kontrakt objęty własnością. Dlatego wykorzystanie wzorca dostępu opartego na rolach dla kilku kont administratorów może być lepszym rozwiązaniem.
W przypadku kontroli dostępu opartej na rolach dostęp do wrażliwych funkcji jest rozdysponowany pomiędzy zaufanymi uczestnikami. Na przykład jedno konto może być odpowiedzialne za mintowanie tokenów, a inne może mieć możliwość zatrzymania kontraktu lub jego aktualizacji. Decentralizowanie kontroli dostępu w taki sposób, eliminuje pojedyncze punkty awarii i ogranicza potrzebę użytkowników do powierzania zaufania.
Używanie portfelu multisig
Innym podejściem do implementacji bezpiecznej kontroli dostępu jest użycie konta z wieloma podpisami do zarządzania kontraktem. W przeciwieństwie do EOA, konta multisig mają kilku właścicieli i wymagają podpisów od określonej minimalnej liczby kont — na przykład 3 z 5 — aby wykonać transakcję.
Używanie multisig do kontroli dostępu wprowadza dodatkową warstwę bezpieczeństwa, ponieważ czynności na docelowym kontrakcie wymagają zgody kilku stron. Jest to szczególnie użyteczne, kiedy wykorzystanie wzorca własności jest niezbędne, ponieważ czyni on manipulacje wrażliwymi funkcjami kontraktu w złośliwych celach trudniejszymi dla napastnika czy wewnętrznego sabotażysty.
2. Używaj instrukcji require(), assert() i revert() do ochrony operacji kontraktowych
Jak wspomniano, każdy może wywoływać funkcje publiczne w inteligentnym kontrakcie po jego wdrożeniu w blockchainie. Ponieważ nie można z góry przewidzieć, w jaki sposób konta zewnętrzne będą oddziaływać na umowę, najlepszym rozwiązaniem jest wdrożenie wewnętrznych zabezpieczeń chroniących przed problematycznymi operacjami przed wdrożeniem. Możesz wymusić poprawne zachowanie w inteligentnych kontraktach za pomocą instrukcji require(), assert() i revert(), aby wywoływać wyjątki i cofać zmiany stanu, jeśli wykonanie nie spełni określonych wymagań.
require(): Instrukcje require są definiowane na początku funkcji i zapewniają, że określone warunki są spełnione, zanim wywołana funkcja zostanie wykonana. Instrukcja require może być użyta do walidacji danych wejściowych użytkownika, sprawdzania zmiennych stanu lub uwierzytelniania tożsamości konta wywołującego przed kontynuowaniem wykonania funkcji.
assert(): assert() służy do wykrywania błędów wewnętrznych i sprawdzania naruszeń „niezmienników” w kodzie. Niezmiennik to logiczne założenie dotyczące stanu kontraktu, które powinno być prawdziwe dla wszystkich możliwych wykonań funkcji. Przykładowym niezmiennikiem jest maksymalna podaż całkowita lub saldo w kontrakcie tokena. Użycie assert() zapewnia, że kontrakt nigdy nie osiągnie stanu podatności na ataki, a jeśli tak się stanie, wszystkie zmiany w zmiennych stanu zostaną wycofane.
revert(): revert() może być użyte w instrukcji if-else, która wywołuje wyjątek, jeśli wymagany warunek nie jest spełniony. Poniższy przykładowy kontrakt wykorzystuje revert() do ochrony wykonywania funkcji:
1pragma solidity ^0.8.4;23contract VendingMachine {4 address owner;5 error Unauthorized();6 function buy(uint amount) public payable {7 if (amount > msg.value / 2 ether)8 revert("Za mało Etheru.");9 // Dokonaj zakupu.10 }11 function withdraw() public {12 if (msg.sender != owner)13 revert Unauthorized();1415 payable(msg.sender).transfer(address(this).balance);16 }17}Pokaż wszystko3. Testuj inteligentne kontrakty i weryfikuj poprawność kodu
Niezmienność kodu działającego w Wirtualnej Maszynie Ethereum oznacza, że inteligentne kontrakty wymagają wyższego poziomu oceny jakości na etapie rozwoju. Dokładne testowane kontraktu i obserwowanie go w celu wychwycenia wszelkich nieoczekiwanych rezultatów, wzmocni znacząco jego bezpieczeństwo i, w dłuższym okresie, ochroni użytkowników.
Standardową metodą jest pisanie małych testów jednostkowych, używając nieprawdziwych danych, które powinny zostać dostarczone do kontraktu przez użytkowników. Testowanie jednostkowe jest dobre do testowania funkcjonalności poszczególnych funkcji i upewniania się, że inteligentny kontrakt działa zgodnie z oczekiwaniami.
Niestety testowanie jednostkowe jest niezbyt efektywne w kwestii zwiększania poziomu zabezpieczenia inteligentnego kontraktu, kiedy stosuje się je jako jedyną metodę. Test jednostkowy może dowieźć, że funkcja działa poprawnie dla nieprawdziwych danych, ale skuteczność testów jednostkowych ogranicza się do jakości napisanych testów. To zwiększa trudność wykrycia pominiętych przypadków granicznych czy słabych punktów, których wykorzystanie może złamać zabezpieczenia inteligentnego kontraktu.
Lepszym podejściem jest połączenie testowania jednostkowego z testowaniem opartym na właściwościach, przeprowadzanym przy użyciu analizy statycznej i dynamicznej. Analiza statyczna opiera się na reprezentacjach niskiego poziomu, takich jak grafy przepływu sterowaniaopens in a new tab i abstrakcyjne drzewa składniopens in a new tab, w celu analizy osiągalnych stanów programu i ścieżek wykonania. Tymczasem techniki analizy dynamicznej, takie jak fuzzing inteligentnych kontraktówopens in a new tab, wykonują kod kontraktu z losowymi wartościami wejściowymi w celu wykrycia operacji naruszających właściwości bezpieczeństwa.
Weryfikacja formalna to kolejna technika weryfikacji właściwości bezpieczeństwa w inteligentnych kontraktach. W przeciwieństwie do zwykłego testowania weryfikacja formalna może jednoznacznie dowieźć braku obecności błędów w inteligentnym kontrakcie. Osiąga się to poprzez tworzenie formalnej specyfikacji, która określa pożądane właściwości zabezpieczeń i dowodzi, że model formalny kontraktów spełnia założenia tej specyfikacji.
4. Poproś o niezależny przegląd swojego kodu
Po przetestowaniu kontraktu dobrze jest poprosić innego programistę o sprawdzenie kodu źródłowego w celu wykrycia problemów dotyczących zabezpieczeń. Testowanie nie odkryje każdej wady inteligentnego kontraktu, ale zapewnienie niezależnej recenzji zwiększy prawdopodobieństwo wykrycia słabych punktów.
Audyty
Zlecenie audytu inteligentnego kontraktu jest jednym ze sposobów na przeprowadzenie niezależnej recenzji kodu. Audytorzy odgrywają ważną rolę w zapewnieniu bezpieczeństwa inteligentnemu kontraktowi oraz sprzyjają pozbyciu się defektów i błędów projektowych.
Nie powinno to jednak doprowadzić do sytuacji, w której audyty stanowią jedyne zastosowane rozwiązanie. Audyty inteligentnych kontraktów nie wyłapią każdego błędu i są głównie zaprojektowane, aby zapewnić dodatkowy cykl recenzji, który może pomóc w wykryciu problemów przeoczonych przez programistów podczas początkowych etapów programowania oraz testów. Powinno się również stosować do najlepszych praktyk we współpracy z audytorami, które obejmują odpowiednie dokumentowanie kodu oraz dodawanie komentarzy w celu maksymalizacji korzyści płynących z audytu inteligentnego kontraktu.
- Porady i wskazówki dotyczące audytu inteligentnych kontraktówopens in a new tab – @tinchoabbate
- Wykorzystaj w pełni swój audytopens in a new tab – Inference
Nagrody za znalezienie błędów
Zorganizowanie programu nagród za znalezienie błędu jest kolejnym podejściem do wdrożenia zewnętrznych recenzji kodu. Nagroda za znalezienie błędu jest finansową gratyfikacją przyznawaną osobom (zwykle hakerom w białych kapeluszach), które wykryją słabe punkty aplikacji.
Gdy są odpowiednio wykorzystane, nagrody za znalezienie błędu dają członkom społeczności hakerskiej zachętę do inspekcji kodu pod kątem wad krytycznych. Przykładem z życia wziętym jest „błąd nieskończonej ilości pieniędzy”, który pozwoliłby atakującemu na stworzenie nieograniczonej ilości etheru na Optimismopens in a new tab, protokole Warstwy 2 działającym na Ethereum. Na szczęście haker w białym kapeluszu odkrył tę wadęopens in a new tab i powiadomił zespół, otrzymując przy tym dużą nagrodęopens in a new tab.
Przydatną strategią jest ustalanie wysokości nagrody w proporcji do wartości zagrożonych środków. Podejście to, określane mianem „skalowalnych nagród za błędyopens in a new tab”, zapewnia zachęty finansowe dla osób, które w sposób odpowiedzialny ujawniają luki w zabezpieczeniach, zamiast je wykorzystywać.
5. Postępuj zgodnie z najlepszymi praktykami podczas tworzenia inteligentnych kontraktów
Istnienie audytów i programów nagród za znalezienie błędu nie zwalnia z odpowiedzialności za pisanie kodu wysokiej jakości. Dobre zabezpieczenie inteligentnego kontraktu zaczyna się na etapie projektowania i programowania:
-
Przechowuj całość kodu w systemie kontroli wersji takim jak git
-
Dokonywać każdej modyfikacji kodu za pomocą żądania Pull
-
Upewnić się, że żądania Pull mają przynajmniej jednego niezależnego recenzenta, co oznacza, że jeśli samodzielnie pracujesz przy projekcie, powinieneś rozważyć kontakt z innymi programistami w celu wymiany ocen kodu
-
Używaj środowiska deweloperskiego do testowania, kompilowania i wdrażania inteligentnych kontraktów
-
Przetestuj swój kod za pomocą podstawowych narzędzi do analizy kodu, takich jak Cyfrin Aderynopens in a new tab, Mythril i Slither. W idealnych warunkach powinno się robić to przed scaleniem każdego żądania pull, a następnie porównać różnice w danych wyjściowych
-
Upewnić się, że kod kompiluje się bez błędów, oraz że kompilator Solidity nie pokazuje żadnych ostrzeżeń
-
Odpowiednio dokumentuj swój kod (używając NatSpecopens in a new tab) i opisuj szczegóły dotyczące architektury kontraktu w łatwym do zrozumienia języku. Ułatwi to innym przeprowadzenie audytu i recenzji kodu.
6. Wdróż solidne plany odzyskiwania po awarii
Projektowanie bezpiecznej kontroli dostępu, implementowanie modyfikatorów funkcji oraz inne sugestie mogą zwiększyć bezpieczeństwo inteligentnego kontraktu, ale nie mogą wykluczyć ryzyka złośliwego wykorzystania. Tworzenie bezpiecznych inteligentnych kontraktów wymaga "przygotowania się na porażkę" oraz posiadania planu zapasowego na efektywną odpowiedź wobec ataku. Odpowiedni plan odzyskiwania w przypadku katastrofy powinien zawierać następujące komponenty:
Aktualizacje kontraktów
Pomimo tego, że standardowo inteligentne kontrakty Ethereum są niezmienne, możliwe jest osiągnięcie pewnego poziomu zmienności przy użyciu wzorców aktualizacji. Aktualizacja kontraktu jest niezbędne w przypadkach, w których wada krytyczna sprawia, że kontrakt staje się bezużyteczny, a wdrożenie nowej logiki jest najbardziej wykonalną możliwością.
Mechanizmy aktualizowania kontraktu działają na różne sposoby, ale "wzorzec proxy" jest jednym z najbardziej popularnych podejść do aktualizowania inteligentnych kontraktów. Wzorce proxyopens in a new tab dzielą stan i logikę aplikacji między dwa kontrakty. Pierwszy kontrakt (nazywany „kontraktem proxy”) przechowuje zmienne stanu (np. salda użytkowników), natomiast drugi kontrakt (nazywany „kontraktem logicznym”) zawiera kod do wykonywania funkcji kontraktu.
Konta wchodzą w interakcję z kontraktem proxy, który przekazuje wszystkie wywołania funkcji do kontraktu logicznego za pomocą niskopoziomowego wywołania delegatecall()opens in a new tab. W przeciwieństwie do zwykłego wywołania wiadomości, delegatecall() zapewnia, że kod działający pod adresem kontraktu logicznego jest wykonywany w kontekście kontraktu wywołującego. Oznacza to, że kontrakt logiczny zawsze będzie zapisywał dane w pamięci masowej proxy (zamiast we własnej), a oryginalne wartości msg.sender i msg.value zostaną zachowane.
Delegowanie wywołań do kontraktu logicznego wymaga przechowywania jego adresu w pamięci kontraktu proxy. Dlatego aktualizacja logiki kontraktu jest jedynie kwestią wdrożenia kolejnego kontraktu logicznego i przechowania nowego adresu w kontrakcie proxy. Jako że kolejne wywołania kontraktu proxy są automatycznie przekierowane do nowego kontraktu logicznego, "aktualizacja" została dokonana właściwie bez modyfikacji kodu.
Więcej o aktualizowaniu kontraktów.
Zatrzymania awaryjne
Jak wspomniano wcześniej, nawet dokładne audyty i testowanie nie są w stanie odkryć dokładnie wszystkich błędów w inteligentnym kontrakcie. Jeśli luka w zabezpieczeniach ujawni się w kodzie już po wdrożeniu, załatanie jej nie jest możliwe, ponieważ nie można zmienić kodu uruchomionego pod adresem kontraktu. Ponadto, implementacja mechanizmów aktualizacji (np. wzorca proxy) mogą zająć czas (wymagają one często zgody wielu stron), co działa tylko na korzyść napastników, dając im więcej czasu na dokonanie szkód.
Opcją nuklearną jest implementacja funkcji "wyłącznika awaryjnego", która blokuje wywołania zagrożonych funkcji kontraktu. Wyłączniki awaryjne zawierają zwykle następujące komponenty:
-
Globalną zmienną logiczną, która wykazuje czy inteligentny kontrakt jest w stanie zatrzymania czy nie. Zmienna ta jest ustawiona na
falsepodczas konfigurowania kontraktu, ale powróci do wartościtrue, gdy kontrakt zostanie zatrzymany. -
Funkcje, które odnoszą się do zmiennej logicznej w swoim działaniu. Takie funkcje są dostępne, kiedy inteligentny kontrakt nie jest zatrzymany, a przestają być dostępne, kiedy funkcja awaryjnego wyłącznika zostaje aktywowana.
-
Podmiot, który ma dostęp do funkcji zatrzymania awaryjnego, która ustawia zmienną logiczną na
true. Aby uniknąć złośliwych działań, wywołania tej funkcji mogą zostać ograniczone do zaufanych adresów (np. właściciela kontraktu).
Kiedy kontrakt aktywuje wyłącznik awaryjny, określone funkcje przestaną być dostępne. Osiąga się to poprzez opakowanie wybranych funkcji modyfikatorem, który odnosi się do zmiennej globalnej. Poniżej znajduje się przykładopens in a new tab opisujący implementację tego wzorca w kontraktach:
1// Ten kod nie został profesjonalnie zaudytowany i nie daje żadnych gwarancji bezpieczeństwa ani poprawności. Używaj na własne ryzyko.23contract EmergencyStop {45 bool isStopped = false;67 modifier stoppedInEmergency {8 require(!isStopped);9 _;10 }1112 modifier onlyWhenStopped {13 require(isStopped);14 _;15 }1617 modifier onlyAuthorized {18 // Tutaj sprawdź autoryzację msg.sender19 _;20 }2122 function stopContract() public onlyAuthorized {23 isStopped = true;24 }2526 function resumeContract() public onlyAuthorized {27 isStopped = false;28 }2930 function deposit() public payable stoppedInEmergency {31 // Tutaj odbywa się logika depozytu32 }3334 function emergencyWithdraw() public onlyWhenStopped {35 // Tutaj odbywa się awaryjna wypłata36 }37}Pokaż wszystkoTen przykład ukazuje podstawowe cechy wyłączników awaryjnych:
-
isStoppedto zmienna logiczna, która na początku ma wartośćfalse, a po przejściu kontraktu w tryb awaryjny –true. -
Modyfikatory funkcji
onlyWhenStoppedistoppedInEmergencysprawdzają zmiennąisStopped.stoppedInEmergencysłuży do kontrolowania funkcji, które powinny być niedostępne, gdy kontrakt jest podatny na ataki (np.deposit()). Wywołania tej funkcji po prostu zostaną anulowane.
onlyWhenStopped jest używany dla funkcji, które powinny być możliwe do wywołania w sytuacji awaryjnej (np. emergencyWithdraw()). Takie funkcje mogą pomóc w rozwiązaniu sytuacji, dlatego wykluczone są z listy "zastrzeżonych funkcji".
Użycie funkcji wyłącznika awaryjnego zapewnia efektywne rozwiązanie tymczasowe pozwalające poradzić sobie z poważnymi podatnościami inteligentnego kontraktu. Zwiększa jednak potrzebę zaufania wobec programistów, że nie użyją jej dla własnej korzyści. Aby się to tego odnieść, można użyć środków takich jak decentralizacja kontroli nad wyłącznikami awaryjnymi poprzez poddanie jej pod mechanizm głosowania onchain, zamku czasowego lub użycia do jej kontroli portfela multisig.
Monitorowanie zdarzeń
Zdarzeniaopens in a new tab pozwalają śledzić wywołania funkcji inteligentnych kontraktów i monitorować zmiany zmiennych stanu. Zaleca się programowanie kontraktów w taki sposób, aby emitowały zdarzenie za każdym razem, gdy jakiś podmiot wykonuje czynność istotną z perspektywy zabezpieczeń (np. wypłatę środków).
Rejestrowanie zdarzeń i monitorowanie ich offchain zapewnia wgląd do operacji kontraktu i pomaga w szybszym odkrywaniu złośliwych czynności. Oznacza to, że zespół może szybciej odpowiedzieć na haki i zacząć działać, aby ograniczyć negatywny wpływ grożący użytkownikom, np. zatrzymując funkcje lub wykonując aktualizację.
Można również zdecydować się na gotowe narzędzie do monitorowania, które automatycznie przekazuje ostrzeżenia za każdym razem, kiedy ktoś wchodzi w interakcję z kontraktem. Narzędzia te pozwalają stworzyć niestandardowe powiadomienia wywoływane różnymi wyzwalaczami takimi jak wielkość wolumenu transakcji, częstotliwość wywoływania funkcji oraz użycie określonych funkcji. Na przykład można zaprogramować powiadomienie, który przychodzi, kiedy suma wypłacona w jednej transakcji przekracza określony próg.
7. Projektuj bezpieczne systemy zarządzania
Warte rozważenia jest zdecentralizowanie aplikacji poprzez oddanie kontroli nad kluczowymi inteligentnymi kontraktami członkom społeczności. W tym przypadku system inteligentnego kontraktu będzie zawierał moduł zarządzający — mechanizm, który pozwala członkom społeczności aprobować czynności administracyjne poprzez system zarządzania onchain. Na przykład propozycja aktualizacji kontraktu proxy do nowej wersji może być poddana głosowaniu posiadaczom tokena.
Zdecentralizowane zarządzanie może być korzystne, ponieważ czyni zbieżnym interes programistów oraz użytkowników końcowych. Niemniej mechanizmy zarządzania inteligentnymi kontraktami mogą wprowadzić nowe ryzyka w przypadku niepoprawnej implementacji. Prawdopodobnym scenariuszem jest sytuacja, w której atakujący zdobywa ogromną siłę głosu (mierzoną liczbą posiadanych tokenów) poprzez wzięcie błyskawicznej pożyczki i przeforsowuje złośliwą propozycję.
Jednym ze sposobów zapobiegania problemom związanym z zarządzaniem on-chain jest użycie blokady czasowej (timelock)opens in a new tab. Zamek czasowy powstrzymuje inteligentny kontrakt przed wykonaniem pewnej funkcji, zanim minie określona ilość czasu. Inne strategie przewidują nadanie "ciężaru głosu" każdemu tokenowi na bazie czasu, na jaki został zablokowany lub zmierzenie siły adresu w przeszłym okresie (na przykład 2 czy 3 bloki wstecz) zamiast w czasie aktualnego bloku. Obie metody obniżają ryzyko szybkiego gromadzenia siły głosu, aby przechylić na swoją korzyść głosowania onchain.
Więcej na temat projektowania bezpiecznych systemów zarządzaniaopens in a new tab, różnych mechanizmów głosowania w DAOopens in a new tab oraz powszechnych wektorów ataków na DAO wykorzystujących DeFiopens in a new tab w udostępnionych linkach.
8. Ogranicz złożoność kodu do minimum
Programiści tradycyjnego oprogramowania są zaznajomieni z zasadą KISS ("ma być prosto głupku"), która odradza wprowadzania niepotrzebnej złożoności do projektu oprogramowania. Jest to zgodne ze znanym od dawana stwierdzeniem, że "złożone systemy zawodzą w złożone sposoby" oraz są najbardziej podatne na kosztowne błędy.
Zachowanie prostoty jest szczególnie ważne przy pisaniu inteligentnych kontraktów, jeśli weźmiemy pod wagę fakt, że inteligentne kontrakty mogą potencjalnie kontrolować aktywa o wysokiej wartości. Wskazówką pozwalającą na osiągnięcie prostoty podczas pisania inteligentnych kontraktów jest ponowne wykorzystywanie istniejących bibliotek, takich jak OpenZeppelin Contractsopens in a new tab, tam, gdzie to możliwe. Biblioteki te bowiem poddane były dokładnym audytom oraz testom prowadzonym przez programistów. Używanie ich ogranicza ryzyko popełnienia błędu podczas pisania nowych funkcji od zera.
Inną powszechną wskazówką jest pisanie niewielkich funkcji i dbanie o modularność kontraktów poprzez rozdzielanie logiki biznesowej pomiędzy wiele kontraktów. Pisanie prostszego kodu nie tylko ogranicza powierzchnię potencjalnego ataku w inteligentnym kontrakcie, ale również ułatwia rozważania na temat poprawności całego systemu oraz szybkie wykrywanie możliwych błędów projektowych.
9. Chroń się przed powszechnymi lukami w zabezpieczeniach inteligentnych kontraktów
Ponowne wejście (reentrancy)
EVM nie pozwala na współbieżność w takim znaczeniu, że dwa kontrakty biorące udział w wywołaniu komunikatu nie mogą działać jednocześnie. Zewnętrzne wywołanie zatrzymuje działanie kontraktu wywołującego oraz jego pamięć do czasu powrotu wywołania. Po tym fakcie działanie jest wznowione. Proces ten można formalnie opisać jako przekazanie przepływu sterowaniaopens in a new tab do innego kontraktu.
W większości przypadków jest to nieszkodliwe, ale przenoszenie kontroli przepływu do niezaufanych kontaktów może powodować problemy takie jak atak rekurencyjny. Atak rekurencyjny występuje, gdy złośliwy kontrakt powraca wywołanie do narażonego kontraktu, zanim wywołanie właściwej funkcji dobiegnie końca. Najlepiej wyjaśnić to za pomocą przykładu.
Weźmy prosty inteligentny kontrakt ("Ofiarę"), który pozwala każdemu na deponowanie i wypłacanie eteru:
1// Ten kontrakt jest podatny na ataki. Nie używać w środowisku produkcyjnym23contract Victim {4 mapping (address => uint256) public balances;56 function deposit() external payable {7 balances[msg.sender] += msg.value;8 }910 function withdraw() external {11 uint256 amount = balances[msg.sender];12 (bool success, ) = msg.sender.call.value(amount)("");13 require(success);14 balances[msg.sender] = 0;15 }16}Pokaż wszystkoTen kontrakt udostępnia funkcję withdraw(), aby umożliwić użytkownikom wypłatę ETH wcześniej zdeponowanego w kontrakcie. Przetwarzając wypłatę, kontrakt dokonuje następujących działań:
- Sprawdza saldo ETH użytkownika
- Wysyła środki na wywołujący adres
- Resetuje ich saldo do 0 uniemożliwiając dalszych wypłat temu użytkownikowi
Funkcja withdraw() w kontrakcie Victim jest zgodna ze wzorcem „sprawdzenie-interakcje-efekty”. Sprawdza, czy warunki niezbędne do wykonania są spełnione (tj. użytkownik ma dodatnie saldo ETH) i wykonuje interakcję, wysyłając ETH na adres wywołującego, przed zastosowaniem efektów transakcji (tj. zmniejszeniem salda użytkownika).
Jeśli funkcja withdraw() jest wywoływana z konta zewnętrznego (EOA), funkcja wykonuje się zgodnie z oczekiwaniami: msg.sender.call.value() wysyła ETH do wywołującego. Jeśli jednak msg.sender jest kontem inteligentnego kontraktu, które wywołuje withdraw(), wysłanie środków za pomocą msg.sender.call.value() spowoduje również uruchomienie kodu zapisanego pod tym adresem.
Wyobraź sobie, że to jest kod wdrożony na adresie kontraktu:
1 contract Attacker {2 function beginAttack() external payable {3 Victim(victim_address).deposit.value(1 ether)();4 Victim(victim_address).withdraw();5 }67 function() external payable {8 if (gasleft() > 40000) {9 Victim(victim_address).withdraw();10 }11 }12}Pokaż wszystkoTen kontrakt jest zaprojektowany, aby wykonywać trzy rzeczy:
- Akceptować depozyt od innego konta (prawdopodobnie od EOA napastnika)
- Dokonać depozytu 1 ETH na kontrakt Ofiary
- Wypłacić ten 1 ETH przechowywany przez inteligentny kontrakt
Nie ma w tym nic złego, z wyjątkiem tego, że Attacker ma inną funkcję, która ponownie wywołuje withdraw() w Victim, jeśli ilość gazu pozostała z przychodzącego msg.sender.call.value jest większa niż 40 000. Daje to Attacker możliwość ponownego wejścia do Victim i wypłacenia większej ilości środków, zanim pierwsze wywołanie withdraw zostanie zakończone. Cykl wygląda następująco:
1- EOA atakującego wywołuje `Attacker.beginAttack()` z 1 ETH2- `Attacker.beginAttack()` wpłaca 1 ETH do `Victim`3- `Attacker` wywołuje `withdraw()` w `Victim`4- `Victim` sprawdza saldo `Attacker` (1 ETH)5- `Victim` wysyła 1 ETH do `Attacker` (co uruchamia funkcję domyślną)6- `Attacker` ponownie wywołuje `Victim.withdraw()` (zauważ, że `Victim` nie zmniejszyło salda `Attacker` po pierwszej wypłacie)7- `Victim` sprawdza saldo `Attacker` (które wciąż wynosi 1 ETH, ponieważ nie zastosowano efektów pierwszego wywołania)8- `Victim` wysyła 1 ETH do `Attacker` (co uruchamia funkcję domyślną i pozwala `Attacker` na ponowne wejście do funkcji `withdraw`)9- Proces powtarza się, dopóki `Attacker` nie wyczerpie gazu, w którym to momencie `msg.sender.call.value` zwraca wartość bez uruchamiania dodatkowych wypłat10- `Victim` w końcu stosuje wyniki pierwszej (i kolejnych) transakcji do swojego stanu, więc saldo `Attacker` jest ustawiane na 0Pokaż wszystkoPodsumowując, z uwagi na to, że saldo wywołującego nie jest ustawione na 0 dopóki wykonanie funkcji nie jest skończone, późniejsze wywołania osiągną sukces i pozwolą wywołującemu wypłacić środki wielokrotnie. Ten rodzaj ataku może być wykorzystany do drenażu środków z inteligentnego kontraktu, jak to miało miejsce podczas ataku na DAO w 2016 rokuopens in a new tab. Ataki typu reentrancy są do dziś krytycznym problemem dla inteligentnych kontraktów, o czym świadczą publiczne listy exploitów reentrancyopens in a new tab.
Jak zapobiegać atakom rekurencyjnym
Jednym ze sposobów radzenia sobie z ponownym wejściem jest przestrzeganie wzorca sprawdzenie-efekty-interakcjeopens in a new tab. Ten wzorzec kieruje wykonaniem funkcji w taki sposób, że w pierwszej kolejności dokonuje niezbędnych sprawdzeń, następnie wykonuje kod zmieniający stan kontraktu, a na końcu kod, który wchodzi w interakcję z kontraktami lub EOA.
Wzorzec sprawdzenie-efekty-interakcje jest użyty w poprawionej wersji kontraktu Victim pokazanej poniżej:
1contract NoLongerAVictim {2 function withdraw() external {3 uint256 amount = balances[msg.sender];4 balances[msg.sender] = 0;5 (bool success, ) = msg.sender.call.value(amount)("");6 require(success);7 }8}Ten kontrakt wykonuje sprawdzenie salda użytkownika, stosuje efekty funkcji withdraw() (zerując saldo użytkownika), a następnie przechodzi do wykonania interakcji (wysłania ETH na adres użytkownika). Dzięki temu kontrakt aktualizuje swoją pamięć przed zewnętrznym wywołaniem, eliminując tym samym warunki do ataku rekurencyjnego, które zaistniały wcześniej. Kontrakt Attacker wciąż może wywołać NoLongerAVictim, ale ponieważ balances[msg.sender] zostało ustawione na 0, dodatkowe wypłaty spowodują błąd.
Innym rozwiązaniem jest zastosowanie wzajemnie wykluczających się zamków (powszechnie znanych pod nazwą "mutex"), które zamykają część stanu kontraktu do czasu zakończenia wywołania funkcji. Jest to realizowane za pomocą zmiennej logicznej, która jest ustawiana na true przed wykonaniem funkcji i wraca do false po zakończeniu wywołania. Jak pokazuje poniższy przykład, używanie mutex zapewnia ochronę przed atakami rekurencyjnymi w czasie, kiedy pierwotne wywołanie wciąż jest przetwarzane.
1pragma solidity ^0.7.0;23contract MutexPattern {4 bool locked = false;5 mapping(address => uint256) public balances;67 modifier noReentrancy() {8 require(!locked, "Zablokowano przed ponownym wejściem.");9 locked = true;10 _;11 locked = false;12 }13 // Ta funkcja jest chroniona przez muteks, więc ponowne wywołania z wewnątrz `msg.sender.call` nie mogą ponownie wywołać `withdraw`.14 // Instrukcja `return` zwraca `true`, ale nadal ocenia instrukcję `locked = false` w modyfikatorze15 function withdraw(uint _amount) public payable noReentrancy returns(bool) {16 require(balances[msg.sender] >= _amount, "Brak salda do wypłaty.");1718 balances[msg.sender] -= _amount;19 (bool success, ) = msg.sender.call{value: _amount}("");20 require(success);2122 return true;23 }24}Pokaż wszystkoMożna również użyć systemu płatności typu pullopens in a new tab, który wymaga od użytkowników wypłacania środków z inteligentnych kontraktów, zamiast systemu „płatności typu push”, który wysyła środki na konta. Eliminuje to możliwość przypadkowego uruchomienia kodu pod nieznanymi adresami (i może również zapobiec niektórym atakom typu „odmowa usługi”).
Niedomiar i przepełnienie liczb całkowitych
Przepełnienie całkowite występuje, gdy wyniki operacji arytmetycznej wykroczą poza dopuszczalny zakres wartości, powodując ich „przesunięcie” do najniższej możliwej do przedstawienia wartości. Na przykład uint8 może przechowywać wartości tylko do 2^8-1=255. Operacje arytmetyczne, których wynik jest większy niż 255, spowodują przepełnienie i zresetowanie uint do 0, podobnie jak licznik kilometrów w samochodzie zeruje się po osiągnięciu maksymalnego przebiegu (999999).
Niedomiar liczb całkowitych zdarza się z podobnych powodów: wynik operacji arytmetycznej mieści się poniżej dopuszczalnego zakresu. Powiedzmy, że próbujesz dekrementować 0 w uint8, wynik po prostu „przewinie się” do maksymalnej reprezentowalnej wartości (255).
Zarówno przepełnienia, jak i niedopełnienia liczb całkowitych mogą prowadzić do nieoczekiwanych zmian zmiennych stanu kontraktu i skutkować nieplanowanym wykonaniem. Poniżej znajduje się przykład pokazujący, w jaki sposób atakujący może wykorzystać przepełnienie arytmetyczne w inteligentnym kontrakcie do wykonania nieprawidłowej operacji:
1pragma solidity ^0.7.6;23// Ten kontrakt ma działać jako skarbiec czasowy.4// Użytkownik może wpłacać środki do tego kontraktu, ale nie może ich wypłacić przez co najmniej tydzień.5// Użytkownik może również wydłużyć czas oczekiwania poza 1-tygodniowy okres.67/*81. Wdróż TimeLock92. Wdróż Attack z adresem TimeLock103. Wywołaj Attack.attack wysyłając 1 ether. Natychmiast będziesz mógł11 wypłacić swój ether.1213Co się stało?14Atak spowodował przepełnienie TimeLock.lockTime i umożliwił wypłatę15przed upływem 1-tygodniowego okresu oczekiwania.16*/1718contract TimeLock {19 mapping(address => uint) public balances;20 mapping(address => uint) public lockTime;2122 function deposit() external payable {23 balances[msg.sender] += msg.value;24 lockTime[msg.sender] = block.timestamp + 1 weeks;25 }2627 function increaseLockTime(uint _secondsToIncrease) public {28 lockTime[msg.sender] += _secondsToIncrease;29 }3031 function withdraw() public {32 require(balances[msg.sender] > 0, "Niewystarczające środki");33 require(block.timestamp > lockTime[msg.sender], "Czas blokady nie upłynął");3435 uint amount = balances[msg.sender];36 balances[msg.sender] = 0;3738 (bool sent, ) = msg.sender.call{value: amount}("");39 require(sent, "Nie udało się wysłać Etheru");40 }41}4243contract Attack {44 TimeLock timeLock;4546 constructor(TimeLock _timeLock) {47 timeLock = TimeLock(_timeLock);48 }4950 fallback() external payable {}5152 function attack() public payable {53 timeLock.deposit{value: msg.value}();54 /*55 jeśli t = bieżący czas blokady, musimy znaleźć x takie, że56 x + t = 2**256 = 057 więc x = -t58 2**256 = type(uint).max + 159 więc x = type(uint).max + 1 - t60 */61 timeLock.increaseLockTime(62 type(uint).max + 1 - timeLock.lockTime(address(this))63 );64 timeLock.withdraw();65 }66}Pokaż wszystkoJak zapobiegać niedomiarom i przepełnieniom całkowitym
Od wersji 0.8.0 kompilator Solidity odrzuca kod powodujący przepełnienia i niedopełnienia liczb całkowitych. Jednakże kontrakty skompilowane przy użyciu niższej wersji kompilatora powinny albo wykonywać sprawdzenia funkcji obejmujących operacje arytmetyczne, albo używać biblioteki (np. SafeMathopens in a new tab), która sprawdza niedomiar/przepełnienie.
Manipulacja wyroczniami
Wyrocznie pozyskują informacje spoza łańcucha (off-chain) i przesyłają je do łańcucha (on-chain) do wykorzystania przez inteligentne kontrakty. Dzięki wyroczniom można projektować inteligentne kontrakty, które współpracują z systemami off-chain, takimi jak rynki kapitałowe, co znacznie rozszerza ich zastosowanie.
Jeśli jednak wyrocznia jest uszkodzona i wysyła nieprawidłowe informacje w łańcuchu, inteligentne kontrakty będą wykonywane w oparciu o błędne dane wejściowe, co może powodować problemy. To jest podstawa „problemu wyroczni”, który dotyczy zadania upewnienia się, że informacje z wyroczni blockchain są dokładne, aktualne i aktualne.
Podobnym problemem bezpieczeństwa jest korzystanie z wyroczni łańcuchowej, takiej jak zdecentralizowana giełda, w celu uzyskania bieżącej ceny aktywów. Platformy pożyczkowe w branży zdecentralizowanych finansów (DeFi) często robią to, aby określić wartość zabezpieczenia użytkownika w celu ustalenia, ile może on pożyczyć.
Ceny DEX są często dokładne, głównie dzięki arbitrażystom przywracającym parytet na rynkach. Są one jednak podatne na manipulację, szczególnie jeśli wyrocznia on-chain oblicza ceny aktywów w oparciu o historyczne wzorce handlowe (co zwykle ma miejsce).
Przykładowo, atakujący może sztucznie zawyżać cenę spot aktywów, zaciągając pożyczkę błyskawiczną tuż przed podpisaniem umowy kredytowej. Zapytanie o cenę aktywów na giełdzie DEX zwróciłoby wyższą niż zwykle wartość (z powodu dużego „zlecenia kupna” atakującego, zaburzającego popyt na aktywa), co umożliwiłoby mu pożyczenie większej kwoty, niż powinien. Tego typu „błyskawiczne ataki kredytowe” wykorzystywano w celu wykorzystania zależności aplikacji DeFi od wyroczni cenowych, co kosztowało protokoły miliony dolarów w postaci utraconych środków.
Jak zapobiegać manipulacjom wyrocznią
Minimalnym wymogiem, aby uniknąć manipulacji wyroczniąopens in a new tab, jest korzystanie ze zdecentralizowanej sieci wyroczni, która pobiera informacje z wielu źródeł, aby uniknąć pojedynczych punktów awarii. W większości przypadków zdecentralizowane wyrocznie mają wbudowane zachęty kryptoekonomiczne, które mają skłaniać węzły wyroczni do raportowania prawidłowych informacji, dzięki czemu są bezpieczniejsze niż wyrocznie scentralizowane.
Jeśli planujesz wysłać zapytanie do wyroczni onchain o ceny aktywów, rozważ użycie takiej, która implementuje mechanizm średniej ceny ważonej w czasie (TWAP). Wyrocznia TWAPopens in a new tab wysyła zapytanie o cenę aktywa w dwóch różnych punktach w czasie (które można modyfikować) i oblicza cenę spot na podstawie uzyskanej średniej. Wybór dłuższych okresów czasu chroni protokół przed manipulacją cenami, ponieważ duże zlecenia zrealizowane niedawno nie mają wpływu na ceny aktywów.
Zasoby dotyczące bezpieczeństwa inteligentnych kontraktów dla programistów
Narzędzia do analizy inteligentnych kontraktów i weryfikacji poprawności kodu
-
Narzędzia i biblioteki testowe – Zbiór standardowych narzędzi i bibliotek do przeprowadzania testów jednostkowych oraz analizy statycznej i dynamicznej inteligentnych kontraktów.
-
Narzędzia do weryfikacji formalnej – narzędzia do weryfikacji poprawności funkcjonalnej w inteligentnych kontraktach i sprawdzania niezmienników.
-
Usługi audytu inteligentnych kontraktów – Lista organizacji świadczących usługi audytu inteligentnych kontraktów dla projektów deweloperskich Ethereum.
-
Platformy nagród za błędy – Platformy do koordynowania nagród za błędy i nagradzania za odpowiedzialne ujawnianie krytycznych luk w zabezpieczeniach inteligentnych kontraktów.
-
Fork Checkeropens in a new tab – Darmowe narzędzie online do sprawdzania wszystkich dostępnych informacji dotyczących sforkowanego kontraktu.
-
ABI Encoderopens in a new tab – darmowa usługa online do kodowania funkcji kontraktu Solidity i argumentów konstruktora.
-
Aderynopens in a new tab – Statyczny analizator Solidity, przechodzący przez Abstrakcyjne Drzewa Składni (AST) w celu wskazania podejrzanych luk w zabezpieczeniach i drukowania problemów w łatwym do przyswojenia formacie markdown.
Narzędzia do monitorowania inteligentnych kontraktów
- Tenderly Real-Time Alertingopens in a new tab – Narzędzie do otrzymywania powiadomień w czasie rzeczywistym, gdy na Twoich inteligentnych kontraktach lub w portfelach zdarzają się nietypowe lub nieoczekiwane zdarzenia.
Narzędzia do bezpiecznego administrowania inteligentnymi kontraktami
-
Safeopens in a new tab – portfel inteligentnego kontraktu działający na Ethereum, który wymaga minimalnej liczby osób do zatwierdzenia transakcji, zanim będzie mogła ona nastąpić (M-z-N).
-
OpenZeppelin Contractsopens in a new tab – Biblioteki kontraktów do wdrażania funkcji administracyjnych, w tym własności kontraktu, uaktualnień, kontroli dostępu, zarządzania, możliwości wstrzymania i innych.
Usługi audytu inteligentnych kontraktów
-
ConsenSys Diligenceopens in a new tab – Usługa audytu inteligentnych kontraktów, która pomaga projektom w całym ekosystemie blockchain upewnić się, że ich protokoły są gotowe do uruchomienia i zbudowane w celu ochrony użytkowników.
-
CertiKopens in a new tab – Firma zajmująca się bezpieczeństwem blockchain, pionier w stosowaniu najnowocześniejszej technologii weryfikacji formalnej w inteligentnych kontraktach i sieciach blockchain.
-
Trail of Bitsopens in a new tab – Firma zajmująca się cyberbezpieczeństwem, która łączy badania nad bezpieczeństwem z mentalnością atakującego, aby zmniejszyć ryzyko i wzmocnić kod.
-
PeckShieldopens in a new tab – Firma zajmująca się bezpieczeństwem blockchain, oferująca produkty i usługi zapewniające bezpieczeństwo, prywatność i użyteczność całego ekosystemu blockchain.
-
QuantStampopens in a new tab – Usługa audytorska ułatwiająca powszechne przyjęcie technologii blockchain poprzez usługi oceny bezpieczeństwa i ryzyka.
-
OpenZeppelinopens in a new tab – Firma zajmująca się bezpieczeństwem inteligentnych kontraktów, która przeprowadza audyty bezpieczeństwa dla systemów rozproszonych.
-
Runtime Verificationopens in a new tab – Firma zajmująca się bezpieczeństwem, specjalizująca się w formalnym modelowaniu i weryfikacji inteligentnych kontraktów.
-
Hackenopens in a new tab – Audytor cyberbezpieczeństwa Web3, który wprowadza kompleksowe podejście (360 stopni) do bezpieczeństwa blockchain.
-
Nethermindopens in a new tab – Usługi audytu Solidity i Cairo, zapewniające integralność inteligentnych kontraktów i bezpieczeństwo użytkowników w sieciach Ethereum i Starknet.
-
HashExopens in a new tab – HashEx koncentruje się na audycie blockchain i inteligentnych kontraktów w celu zapewnienia bezpieczeństwa kryptowalut, świadcząc usługi takie jak tworzenie inteligentnych kontraktów, testy penetracyjne, doradztwo w zakresie blockchain.
-
Code4renaopens in a new tab – Konkurencyjna platforma audytowa, która zachęca ekspertów ds. bezpieczeństwa inteligentnych kontraktów do znajdowania luk w zabezpieczeniach i pomaga uczynić web3 bezpieczniejszym.
-
CodeHawksopens in a new tab – Konkurencyjna platforma audytowa organizująca konkursy audytu inteligentnych kontraktów dla badaczy bezpieczeństwa.
-
Cyfrinopens in a new tab – potęga bezpieczeństwa Web3, inkubująca bezpieczeństwo kryptowalut poprzez produkty i usługi audytu inteligentnych kontraktów.
-
ImmuneBytesopens in a new tab – Firma zajmująca się bezpieczeństwem Web3, oferująca audyty bezpieczeństwa systemów blockchain za pośrednictwem zespołu doświadczonych audytorów i najlepszych w swojej klasie narzędzi.
-
Oxorioopens in a new tab – Audyty inteligentnych kontraktów i usługi bezpieczeństwa blockchain z doświadczeniem w technologiach EVM, Solidity, ZK, Cross-chain dla firm kryptograficznych i projektów DeFi.
-
Inferenceopens in a new tab – Firma audytorska w zakresie bezpieczeństwa, specjalizująca się w audycie inteligentnych kontraktów dla blockchainów opartych na EVM. Eksperci w dziedzinie audytów umiejący zidentyfikować potencjalne problemy i zasugerować działające rozwiązania do zastosowania przed wdrożeniem._
Platformy bug bounty
-
Immunefiopens in a new tab – Platforma bug bounty dla inteligentnych kontraktów i projektów DeFi, na której badacze bezpieczeństwa przeglądają kod, ujawniają luki w zabezpieczeniach, otrzymują wynagrodzenie i sprawiają, że kryptowaluty są bezpieczniejsze.
-
HackerOneopens in a new tab – Platforma koordynacji luk w zabezpieczeniach i nagród za błędy, która łączy firmy z testerami penetracyjnymi i badaczami cyberbezpieczeństwa.
-
HackenProofopens in a new tab – Ekspercka platforma nagród za błędy dla projektów kryptograficznych (DeFi, inteligentne kontrakty, portfele, CEX i inne), na której specjaliści ds. bezpieczeństwa świadczą usługi selekcji, a badacze otrzymują wynagrodzenie za odpowiednie, zweryfikowane raporty o błędach.
-
Sherlockopens in a new tab – Gwarant w Web3 w zakresie bezpieczeństwa inteligentnych kontraktów, z wypłatami dla audytorów zarządzanymi za pośrednictwem inteligentnych kontraktów, aby zapewnić, że odpowiednie błędy są uczciwie opłacane.
-
CodeHawksopens in a new tab – Konkurencyjna platforma bug bounty, na której audytorzy biorą udział w konkursach i wyzwaniach dotyczących bezpieczeństwa, a (wkrótce) także we własnych prywatnych audytach.
Publikacje znanych luk w zabezpieczeniach inteligentnych kontraktów i exploitów
-
ConsenSys: Znane ataki na inteligentne kontraktyopens in a new tab – Przyjazne dla początkujących wyjaśnienie najważniejszych luk w zabezpieczeniach kontraktów, z przykładowym kodem dla większości przypadków.
-
Rejestr SWCopens in a new tab – Wyselekcjonowana lista elementów Common Weakness Enumeration (CWE), które mają zastosowanie do inteligentnych kontraktów Ethereum.
-
Rektopens in a new tab – Regularnie aktualizowana publikacja głośnych hacków i exploitów kryptograficznych, wraz ze szczegółowymi raportami pośmiertnymi.
Wyzwania związane z nauką bezpieczeństwa inteligentnych kontraktów
-
Awesome BlockSec CTFopens in a new tab – Wyselekcjonowana lista gier wojennych, wyzwań i konkursów Capture The Flagopens in a new tab z zakresu bezpieczeństwa blockchain oraz opisy rozwiązań.
-
Damn Vulnerable DeFiopens in a new tab – Gra wojenna do nauki bezpieczeństwa ofensywnego inteligentnych kontraktów DeFi oraz budowania umiejętności w polowaniu na błędy i audycie bezpieczeństwa.
-
Ethernautopens in a new tab – Gra wojenna oparta na Web3/Solidity, w której każdy poziom jest inteligentnym kontraktem, który należy „zhakować”.
-
HackenProof x HackTheBoxopens in a new tab – Wyzwanie hakerskie dotyczące inteligentnych kontraktów, osadzone w fantastycznej przygodzie. Pomyślne ukończenie wyzwania daje również dostęp do prywatnego programu nagród za znalezienie błędu._
Najlepsze praktyki w zakresie zabezpieczania inteligentnych kontraktów
-
ConsenSys: Najlepsze praktyki w zakresie bezpieczeństwa inteligentnych kontraktów Ethereumopens in a new tab – Kompleksowa lista wytycznych dotyczących zabezpieczania inteligentnych kontraktów Ethereum.
-
Nascent: Prosty zestaw narzędzi bezpieczeństwaopens in a new tab – Zbiór praktycznych przewodników i list kontrolnych dotyczących bezpieczeństwa w tworzeniu inteligentnych kontraktów.
-
Wzorce Solidityopens in a new tab – Użyteczna kompilacja bezpiecznych wzorców i najlepszych praktyk dla języka programowania inteligentnych kontraktów Solidity.
-
Dokumentacja Solidity: Kwestie bezpieczeństwaopens in a new tab – Wytyczne dotyczące pisania bezpiecznych inteligentnych kontraktów za pomocą Solidity.
-
Standard weryfikacji bezpieczeństwa inteligentnych kontraktówopens in a new tab – Czternastoczęściowa lista kontrolna stworzona w celu standaryzacji bezpieczeństwa inteligentnych kontraktów dla programistów, architektów, recenzentów bezpieczeństwa i dostawców.
-
Naucz się bezpieczeństwa i audytu inteligentnych kontraktówopens in a new tab – Kompletny kurs bezpieczeństwa i audytu inteligentnych kontraktów, stworzony dla programistów inteligentnych kontraktów, którzy chcą podnieść swoje najlepsze praktyki w zakresie bezpieczeństwa i stać się badaczami bezpieczeństwa.