Właśnie widzieliśmy, jak mała luka prowadzi do strat finansowych (o różnej wielkości), w podobny sposób inteligentne kontrakty opracowane przez Solidity są podatne na różne znane i nieznane ataki. Wyzyskiwacze wykorzystują błędy i luki, aby zaglądać do inteligentnych kontraktów i manipulować nimi w celu przeprowadzenia ataków. Tutaj przedstawiamy wyczerpującą listę 5 najczęściej spotykanych błędów w języku programowania Solidity.
W QuillAudits stosujemy metodologię adaptacyjną, aby poznać sedno każdego włamania i wdrożyć jego wiedzę na przyszłych inteligentnych kontraktach, aby uniknąć potencjalnego zagrożenia.
Błędy w języku programowania solidności
1. Niesprawdzone połączenie zewnętrzne
W pierwszej kolejności zajmujemy się tym problemem, ponieważ jest to jedna z najczęściej obserwowanych pułapek Solidity. Ogólnie rzecz biorąc, wysyłanie eteru na dowolne konto zewnętrzne odbywa się za pośrednictwem przenosić() funkcjonować. Oprócz tego dwie najczęściej używane funkcje do wykonywania połączeń zewnętrznych to; połączenie(), wysłać(), tutaj głównie połączenie() Funkcja jest szeroko wykorzystywana przez programistów do wykonywania wszechstronnych połączeń zewnętrznych.
Chociaż połączenie() i wysłać() funkcje zwracają wartość logiczną określającą, czy wywołanie zakończyło się sukcesem, czy nie. Tak więc w tym przypadku, jeśli którakolwiek z funkcji połączenie() or wysłać() nie wykona zadania, powrócą z fałsz W związku z tym, jeśli deweloper nie sprawdzi wartości zwracanej, stanie się to pułapką.
Luka w zabezpieczeniach
Rozważ poniższy przykład:
umowa lotto{
boolpublic paydOut =false;
zwracać się do publicznego zwycięzcy;
niepubliczna kwota wygranej;
// … dodatkowa funkcjonalność tutaj
function sendToZinner()public{
wymagać(!wypłacony);
zwycięzca.send(winAmount);
wypłacone = prawda;
}
funkcja wycofajLeftOver()public{
wymagać (wypłacony);
msg.sender.send(to.saldo);
}
}
W powyższej umowie podobnej do Lotto możemy zaobserwować, że a zwycięzca otrzymuje wygrana Kwota eteru, pozostawiając trochę resztek do wycofania z jakiegokolwiek zewnętrznego czynnika.
Tu pułapka kontraktu istnieje w linii [11], gdzie a wysłać jest używany bez weryfikacji krzyżowej odpowiedzi. W powyższym przykładzie a zwycięzca którego transakcja nie powiodła się (albo z powodu niedoboru Gazu, albo jeśli jest to umowa, która celowo włącza funkcję awaryjną), autoryzuje wypłacone być ustawionym na prawdziwy niezależnie od tego, czy transakcja z eterem zakończyła się sukcesem, czy nie. W takim przypadku każdy eksploatator może wycofać zwycięzcy wygrane za pośrednictwem wycofaćLeftOver funkcja.
Podejście QuillAudit
Nasz wewnętrzny zespół programistów rozwiązuje ten błąd za pomocą [przenosić] funkcja zamiast [wysłać] funkcja, ponieważ [transfer] zostanie cofnięty, jeśli transakcja zewnętrzna zostanie cofnięta. A jeśli używasz [wyślij], zawsze sprawdzaj wartość zwracaną.
Jednym z solidnych podejść, które stosujemy, jest wykorzystanie [wzoru wypłat]. Tutaj logicznie izolujemy zewnętrzną funkcję wysyłania od reszty kodu i obciążamy użytkownika końcowego, potencjalnie nieudanymi transakcjami, ponieważ to on wywołuje funkcję wycofania.
2. Ponowne wejście
Inteligentne kontrakty Ethereum wywołują i wykorzystują kody z innych kontraktów zewnętrznych, a do tego wymagane są kontrakty do przesyłania wywołań zewnętrznych. Te połączenia zewnętrzne są podatne na ataki i podatne na ataki, jeden taki atak miał miejsce niedawno w przypadku włamania DAO.
Luka w zabezpieczeniach
Atakujący przeprowadzają takie ataki, gdy umowa wysyła eter na nieznany adres. W takim przypadku osoba atakująca może utworzyć umowę pod adresem zewnętrznym, który zawiera złośliwy kod w funkcji awaryjnej, a ten złośliwy kod zostanie wywołany, gdy umowa wyśle ether na ten adres.
Fakt: Termin „ponowne wejście” został ukuty z tego powodu, że gdy zewnętrzny złośliwy kontrakt wywołuje funkcję nad zagrożonym kontraktem, a następnie ścieżka wykonania kodu „wchodzi w nią ponownie”.
Rozważ poniższy przykład, jest to skarbiec Ethereum, który umożliwia deponentom wypłatę tylko 1 eteru tygodniowo.
umowa EtherStore {
uint256 limit wycofania publicznego = 1 eter;
mapowanie(adres => uint256) public lastWithdrawTime;
mapowanie(adres => uint256) sald publicznych;
function depositFunds() zewnętrzne płatne {
salda[msg.sender] += msg.value;
}
funkcja wycofania funduszy (uint256 _weiToWithdraw) public {
wymagać(salda[msg.sender] >= _weiToWithdraw);
// ogranicz wypłatę
wymagać(_weiToWithdraw <=Limit wypłaty);
// ogranicz czas na wypłatę
wymagaj(teraz >= lastWithdrawTime[msg.sender] + 1 tydzień);
wymagać(msg.sender.call.value(_weiToWithdraw)());
salda[msg.sender] -= _weiToWithdraw;
lastWithdrawTime[msg.sender] = teraz;
}
}
W powyższej umowie mamy dwie funkcje publiczne, [depositFunds] i [withdrawFunds]. [depositFunds] służy do zwiększania salda nadawcy, podczas gdy [withdrawFunds] określa kwotę do wypłaty. W takim przypadku odniesie sukces, jeśli kwota do wypłaty będzie mniejsza niż 1 eter.
Tu pułapka leży w linii [17], w której następuje transfer eteru. Osoba atakująca może stworzyć złośliwy kontrakt z adresem kontraktu [EtherStores] jako jedynym parametrem konstruktora. To uczyniłoby [etherStore] zmienną publiczną, a więc bardziej podatną na ataki.
Podejście QuilllAudit
Stosujemy różne techniki, aby uniknąć potencjalnych luk związanych z ponownym wejściem w inteligentne kontrakty. Pierwszym i najlepszym możliwym sposobem jest użycie wbudowanej funkcji [transfer] podczas przenoszenia eteru na dowolną umowę zewnętrzną.
Po drugie, ważne jest, aby upewnić się, że wszystkie zmiany logiczne w zmiennych stanu należy wykonać przed wysłaniem eteru z umowy. W przykładzie [EtherStore] wiersze [18] i [19] należy umieścić przed wierszem [17].
Trzecia technika może być również wykorzystana do zapobiegania powrotnym wywołaniom; poprzez wprowadzenie muteksu. Jest to dodanie zmiennej stanu, która zablokuje kontrakt podczas wykonywania kodu.
3. Widoczność domyślna
Istnieją specyfikatory widoczności dla funkcji, których używamy w Solidity, i określają sposób ich wywoływania. To widoczność determinuje wywołanie funkcji; zewnętrznie przez użytkowników, przez inne umowy pochodne, tylko wewnętrznie lub tylko zewnętrznie. Przyjrzyjmy się, jak błędne użycie specyfikatorów widoczności może spowodować ogromną podatność inteligentnych kontraktów.
Luka w zabezpieczeniach
Domyślnie widoczność funkcji to [public], stąd użytkownicy zewnętrzni mogą wywoływać funkcje bez określonej widoczności. Błąd pojawia się, gdy programiści zapominają określić widoczność funkcji, które powinny być prywatne (lub mogą być wywołane w ramach samej umowy). Na przykład;
umowa HashForEther {
function wycofajWygrane() {
// Zwycięzca, jeśli ostatnie 8 znaków szesnastkowych adresu to 0
wymagaj(uint32(msg.sender) == 0);
_sendWygrane();
}
function _sendWygrane() {
msg.sender.transfer(to.saldo);
}
}
Powyższa umowa to prosta gra w zgadywanie adresów. Widać tutaj, że widoczność funkcji nie jest określona, w szczególności funkcja [ _sendWinnings] jest [public] (domyślnie), stąd można ją wywołać za pośrednictwem dowolnego adresu, aby ukraść nagrodę.
Podejście QuillAudit
Nasz wewnętrzny zespół składa się z doświadczonych programistów, którzy zawsze stosują najlepsze praktyki audytu, tutaj widoczność funkcji powinna być wyraźnie określona, nawet jeśli mają być upubliczniane, należy o tym wspomnieć.
4. Ochrona użytkowania konstruktorów
Ogólnie rzecz biorąc, konstruktory są nazywane funkcjami specjalnymi, które są używane do wykonywania zadań krytycznych i uprzywilejowanych podczas inicjowania kontraktów. Przed Solidity [v0.4.22] konstruktorzy nosili tę samą nazwę, co umowa, która ich zawierała. Rozważmy teraz przypadek, w którym nazwa kontraktu jest zmieniana w fazie rozwoju, ale nazwa konstruktora pozostaje taka sama. Ta luka może również zapewnić atakującym łatwy dostęp do twojego inteligentnego kontraktu.
Luka w zabezpieczeniach
Może to prowadzić do poważnych konsekwencji, jeśli nazwa kontraktu zostanie zmodyfikowana, ale nazwa konstruktora pozostanie niezmieniona. Na przykład:
Umowa OwnerPortfel {
zwracać się do właściciela publicznego;
// konstruktor
function ownerWallet(adres _owner) public {
właściciel = _właściciel;
}
// Powrót. Zbierz eter.
funkcja () płatna {}
funkcja wycofania() public {
wymagaj(msg.sender == właściciel);
msg.sender.transfer(to.saldo);
}
}
W powyższej umowie widzimy, że tylko właściciel może wycofać ether poprzez wywołanie funkcji [wypłata]. W tym przypadku usterka występuje, ponieważ konstruktor ma inną nazwę niż umowa (pierwsza litera jest inna!). W ten sposób exploiter może wywołać funkcję [ownerWallet] i autoryzować się jako właściciel, a następnie wycofać cały eter w umowie, wywołując [wycofaj].
Podejście QuillAudit
Działamy zgodnie z wersją [0.4.22] kompilatora Solidity. Ta wersja wprowadziła słowo kluczowe; [konstruktor], który wymaga, aby nazwa funkcji była zgodna z nazwą kontraktu.
5. Uwierzytelnianie Tx.Origin
Tutaj [Tx.Origin] jest globalną zmienną Solidity, zawiera adres konta, które pierwotnie wykonało połączenie lub transakcję. Ta zmienna nie może być używana do uwierzytelniania, ponieważ czyni to kontrakt podatnym na ataki typu phishing.
Luka w zabezpieczeniach
Kontrakty autoryzujące użytkowników za pomocą zmiennej [tx.origin] są narażone na ataki zewnętrzne, które prowadzą użytkowników do wykonania uwierzytelnionych działań na błędnym kontrakcie. Rozważ poniższy przykład:
umowa phishingowa {
zwracać się do właściciela publicznego;
konstruktor (adres _właściciel) {
właściciel = _właściciel;
}
function () zewnętrzne płatne {} // zbieraj ether
funkcja wycofajWszystko(adres _odbiorca) public {
wymagaj(tx.origin == właściciel);
_odbiorca.przelew(to.saldo);
}
}
Tutaj, w wierszu [11], kontrakt autoryzuje funkcję [withdrawAll] za pomocą [tx.origin].
Podejście QuillAudit
Generalnie unikamy używania [tx.origin] do autoryzacji w inteligentnych kontraktach. Chociaż użycie [tx.origin] nie jest surowo zabronione, ma pewne specyficzne przypadki użycia. Możemy użyć [tx.origin], aby zabronić zewnętrznym kontraktom wywoływania obecnej umowy, można to wykonać za pomocą [require] postaci [require(tx.origin == msg.sender)]. Ma to na celu uniknięcie wywoływania kontraktów pośrednich w celu wywołania aktualnej umowy, która ogranicza kontrakt do zwykłych adresów bezkodowych.
Ostateczne podsumowanie
Kompleksowo omówiliśmy pięć typowych pułapek w języku Solidity. Opracowując inteligentne kontrakty, nie możemy zapominać, że są one niezmienne z założenia, co oznacza, że po ich stworzeniu nie ma możliwości załatania kodu źródłowego.
Stanowi to wielkie wyzwanie dla programistów, aby przed wdrożeniem skorzystać z dostępnych narzędzi do testowania bezpieczeństwa i audytu.
Wykrywanie potencjalnych złośliwych zagrożeń dla inteligentnych kontraktów oraz zagrożeń, z których niektóre wspomnieliśmy powyżej, jest wykonywane w bardzo wyjątkowy i solidny sposób przez nasz wewnętrzny zespół ekspertów ds. audytu. W QuillAudits dokładamy wszelkich starań w zakresie badań nad bezpieczeństwem, aby Twoja umowa była aktualizowana ze wszystkimi praktykami bezpieczeństwa oprogramowania, aby zapewnić bezpieczeństwo umowy.
Skontaktuj się z QuillHash
Z obecnością w branży od lat, QuillHash dostarcza rozwiązania dla przedsiębiorstw na całym świecie. QuillHash wraz z zespołem ekspertów jest wiodącą firmą zajmującą się rozwojem technologii blockchain, dostarczającą różne rozwiązania branżowe, w tym DeFi Enterprise.Jeśli potrzebujesz pomocy w audycie inteligentnych kontraktów, skontaktuj się z naszymi ekspertami tutaj!
Śledź QuillHash, aby uzyskać więcej aktualizacji
Źródło: https://blog.quillhash.com/2021/06/04/top-5-common-errors-in-solidity-programming-language/
- 11
- Konto
- Korzyść
- Wszystkie kategorie
- Audyt
- Uwierzytelnianie
- autoryzacja
- BEST
- blockchain
- Bug
- błędy
- wezwanie
- Etui
- Spowodować
- wyzwanie
- kod
- wspólny
- sukcesy firma
- umowa
- umowy
- Aktualny
- DAO
- DeFi
- Wnętrze
- Deweloper
- deweloperzy
- oprogramowania
- Enterprise
- Eter
- ethereum
- wydarzenie
- eksperci
- budżetowy
- i terminów, a
- obserwuj
- Nasz formularz
- Darmowy
- funkcjonować
- przyszłość
- gra
- GAS
- Globalne
- wspaniały
- siekać
- tutaj
- W jaki sposób
- HTTPS
- olbrzymi
- Włącznie z
- przemysł
- IT
- język
- prowadzić
- prowadzący
- Linia
- Lista
- Mecz
- Inne
- właściciel
- Łata
- Wzór
- phishing
- ataki phishingowe
- przepisać
- teraźniejszość
- prywatny
- Programowanie
- publiczny
- ciągnięcie
- Badania naukowe
- odpowiedź
- REST
- "bezpiecznym"
- bezpieczeństwo
- Usługi
- zestaw
- Prosty
- mały
- mądry
- inteligentna umowa
- Inteligentne kontrakty
- So
- Tworzenie
- solidność
- Rozwiązania
- Stan
- sukces
- Testowanie
- Źródło
- zagrożenia
- czas
- Top
- top 5
- transakcja
- transakcje
- us
- Użytkownicy
- wartość
- Sklepienie
- widoczność
- Luki w zabezpieczeniach
- wrażliwość
- Wrażliwy
- tydzień
- KIM
- w ciągu
- lat