Podatność na powtarzanie podpisu w inteligentnym kontrakcie | Audyt bloku

Pomocną sztuczką jest podpisywanie wiadomości poza łańcuchem i posiadanie kontraktu, który wymaga tego podpisu przed wykonaniem funkcji.
Technika ta stosowana jest np. w celu:
- zmniejszenia ilości transakcji w łańcuchu
- transakcja bezgazowa, tzwmeta transaction
Zobaczmy o czym mowa
Łańcuchy bloków w dużym stopniu polegają na podpisach kryptograficznych. Transakcje są podpisywane odpowiednimi kluczami prywatnymi, co pozwala na powiązanie nadawców transakcji z ich kontami. Bez tej funkcji księgowość łańcucha bloków nie działałaby.
Podpisy cyfrowe są również często weryfikowane bezpośrednio w inteligentnych kontraktach Ethereum, umożliwiając jednemu lub większej liczbie weryfikatorów autoryzację działań poprzez przesyłanie podpisów poza łańcuchem ( lub nawet podpisów generowanych przez inny inteligentny kontrakt ).
Jest to często używane w skarbcach z wieloma podpisami lub umowach do głosowania w celu jednoczesnego składania wielu podpisów lub delegowania uprawnień.
Częstą luką w takich implementacjach są ataki polegające na powtarzaniu sygnatur.
Weryfikacja podpisu w inteligentnych umowach jest czasami wymagana w celu poprawy użyteczności lub obniżenia kosztów gazu. Bezpieczna implementacja powinna zapobiegać atakom typu Signature Replay.
Na przykład: -
Śledzenie wszystkich przetworzonych skrótów wiadomości i zezwalanie na przetwarzanie tylko nowych skrótów wiadomości. Złośliwy użytkownik może zaatakować kontrakt, który nie ma takiej kontroli i uzyskać skrót wiadomości wysłany przez innego użytkownika i przetworzony wiele razy.
Kryptograficzne podpisy cyfrowe
Podpisy cyfrowe to prymitywy klucza publicznego służące do uwierzytelniania wiadomości. W świecie fizycznym odręczne podpisy są powszechnie używane w wiadomościach pisanych odręcznie lub maszynowo. Służą do powiązania sygnatariusza z wiadomością.
Podpis cyfrowy to wartość kryptograficzna generowana przez dane i tajny klucz znany tylko podpisującemu.
Model podpisu cyfrowego
Cała procedura jest dokładnie wyjaśniona w następujących punktach:

- Każdy użytkownik tego schematu ma zestaw kluczy publicznych i prywatnych.
- Pary kluczy używane do szyfrowania/odszyfrowywania i podpisywania/weryfikacji często różnią się od siebie. Klucz publiczny jest określany jako klucz weryfikacyjny, a klucz prywatny jest określany jako klucz podpisu.
- Dane są wysyłane do funkcji skrótu przez sygnatariusza, który generuje skrót.
- Algorytm podpisu generuje następnie podpis cyfrowy na dostarczonym haszu przy użyciu wartości skrótu i klucza podpisu. Dane są opatrzone podpisem, a następnie oba są przesyłane do weryfikatora.
- Algorytm weryfikacji jest dostarczany przez weryfikatora wraz z podpisem cyfrowym i kluczem weryfikacyjnym. Wynik algorytmu weryfikacji jest czymś użytecznym. Na danych, które otrzymuje, weryfikator również używa tego samego algorytmu mieszania, aby wygenerować wartość skrótu.
- Ta wartość skrótu i wyniki procesu weryfikacji są porównywane w celu weryfikacji. Weryfikator określa, czy podpis cyfrowy jest prawidłowy na podstawie wyników porównania.
- Nikt inny nie może użyć „prywatnego” klucza sygnatariusza do ustanowienia podpisu cyfrowego, stąd sygnatariusz nie może później wycofać swojego podpisu danych.
Warstwa protokołu
Tylko transakcje z ważnymi podpisami są uwzględniane w świeżych blokach dzięki sieci Ethereum . W przypadku transakcji zapewnia to następujące atrybuty bezpieczeństwa:
- Uwierzytelnianie : Podpis jest używany przez węzły Ethereum do potwierdzenia, że osoba podpisująca transakcję jest właścicielem klucza prywatnego połączonego z jej adresem publicznym. Dlatego programiści mogą być pewni, że msg.sender jest autentyczny.
- Integralność : Integralność to warunek, że transakcja nie została zmieniona po podpisaniu; w przeciwnym razie podpis jest nieważny.
- Niezaprzeczalność: podpis transakcji i wszelkie zmiany stanu dokonane przez stronę podpisującą posiadającą klucz prywatny nie mogą być kwestionowane. Klucz prywatny należy do adresu publicznego podanego w polu nadawcy .
Ta sama sygnatura może być używana wielokrotnie do wykonania funkcji. Może to być szkodliwe, jeśli intencją osoby podpisującej było jednorazowe zatwierdzenie transakcji.
Przykład kodu
Zbadajmy błąd.
function unlock(
address _to,
uint256 _amount,
uint8[] _v,
bytes32[] _r,
bytes32[] _s
)
external
{
require(_v.length >= 20);
bytes32 hashData = keccak256(_to, _amount);
for (uint i = 0; i < _v.length; i++) {
address recAddr = ecrecover(hashData, _v[i], _r[i], _s[i]);
require(_isValidator(recAddr));
}
to.transfer(_amount);
}
Wiadomość, która jest podpisana przez walidatory przy użyciu techniki ECDSA, jest przyczyną problemu z wyżej wymienionym kodem. Adres odbiorcy i wymagane pieniądze to jedyne informacje w wiadomości. Nic w wiadomości nie mogło zostać wykorzystane do uniknięcia użycia tego samego podpisu więcej niż jeden raz. Rozważ następujący przypadek:
- Sam przenosi 2000 ETH z połączonej sieci z powrotem do łańcucha Ethereum, używając tej samej kwoty w walucie.
- Przetwarzaniem tej transakcji między łańcuchami bloków zajmuje się Tom, przekaźnik. Aby zwolnić 2000 ETH z kontraktu i wysłać je Samowi, zbiera wymagane podpisy walidatora, blokuje odpowiednią kwotę na połączonym łańcuchu, a następnie korzysta z funkcji odblokowania.
- Na blockchainie transakcja zawierająca tablice wartości sygnatur jest widoczna dla wszystkich.
- Teraz, gdy Sam skopiował tablice sygnatur, może samodzielnie przesłać wywołanie odblokowujące. Po raz kolejny proces odblokowania zakończy się sukcesem, co spowoduje przekazanie Samowi 2000 ETH.
- Sam jest w stanie kontynuować w ten sposób do wyczerpania kontraktu.

Atak polegający na powtórzeniu sygnatury jest opisany w powyższym przykładzie. Jest to możliwe, ponieważ nie ma możliwości ustalenia, czy ta konkretna podpisana wiadomość jest unikalna, czy też była używana wcześniej.
Podpisuj wiadomości za pomocą nonce
i adresu umowy.
public uint256 nonce;
function unlock(
address _to,
uint256 _amount,
uint256 _nonce,
uint8[] _v,
bytes32[] _r,
bytes32[] _s
)
external
{
require(_v.length >= 20);
require(_nonce == nonce++);
bytes32 hashData = keccak256(_to, _amount, _nonce);
for (uint i = 0; i < _v.length; i++) {
address recAddr = ecrecover(hashData, _v[i], _r[i], _s[i]);
require(_isValidator(recAddr));
}
to.transfer(_amount);
}
Aby chronić się przed atakami polegającymi na powtarzaniu sygnatur, należy wziąć pod uwagę następujące zalecenia:
- Przechowuj każdy skrót wiadomości, który został przetworzony przez inteligentną umowę. Po otrzymaniu nowych wiadomości porównaj je z już istniejącymi i postępuj zgodnie z logiką biznesową tylko wtedy, gdy jest to nowy skrót wiadomości.
- Dołącz adres kontraktu przetwarzającego wiadomość. Gwarantuje to, że wiadomość może być użyta tylko w jednej umowie.
- W żadnym wypadku nie generuj skrótu wiadomości zawierającego podpis. Funkcja
ecrecover
jest podatna na plastyczność podpisu.
Nieunikalne podpisy mogą być odtwarzane w różnych sytuacjach, jak widać na powyższym przykładzie. Aby uniknąć ataków polegających na powtórkach, w większości sytuacji kluczowe jest upewnienie się, że podpisy są specjalnie dopasowane do każdego połączenia. Dodatkowo z tego powodu w każdej transakcji Ethereum uwzględniana jest wartość jednorazowa.
Bibliografia: -
https://solidity-by-example.org/hacks/signature-replay/
https://blog.finxter.com/smart-contract-replay-attack-solidity/
https://swcregistry.io/docs/SWC-121
Krzątanie się z zabezpieczeniami web3!!! Połącz się z nami!!!
BlockAudit :- Dlaczego my??
BlockAudit dysponuje zasobami i wiedzą, aby tworzyć rozwiązania w zakresie cyberbezpieczeństwa, które pozwalają zaoszczędzić miliony dolarów.
Linkedin | Strona internetowa | Świergot
