Самостійний аудит смарт-контрактів за допомогою ChatGPT
Під час проведення аудиту смарт-контрактів необхідно охопити широкий спектр питань, щоб упевнитися в безпеці коду. Ці питання охоплюють різні аспекти, зокрема контроль доступу, управління активами, управління даними, допущення, залежності та контрольні списки безпеки. Нижче ми наводимо детальний чек-лист та інструкцію щодо запитів до ChatGPT, які допоможуть вам у процесі аудиту смарт-контракту.
Якщо ви хочете самостійно вивчити смарт-контракт на предмет вразливостей і прихованих методів скаму, то першим кроком буде коректно складений запит (prompt) у ChatGPT.
Корисним запитом для ChatGPT буде така команда:
Надай вичерпний список усіх проблем і вразливостей у наступному смарт-контракті. Детально опиши проблеми та можливі уразливості. Наведи по одному сценарію використання кожної уразливості. Висновок зроби у вигляді коректної таблиці у форматі markdown зі списком об'єктів, кожен з яких має стовпці 'description', 'action', 'severity', 'actors', 'scenario', 'type' і 'line'. 'type' де може бути 'usability', 'vulnerability', 'optimization' або 'suggestion'. 'actors' - це список задіяних суб'єктів. 'серйозність' може бути "низька", "середня" або "висока". 'рядок' - це номер рядка проблеми. Переконайтеся, що всі поля таблиці заповнені.
Далі використовуйте такі запитання, щоб більш глибоко вивчити смарт-контракт.
Сценарії використання:
- Хто є дійовими особами системи?
- Якими діями володіє система?
- Які обмеження існують у системі?
- Які існують потенційні способи зламати систему?
- Який захист використовується для протидії атакам?
- Опиши, виходячи з обмежень, зміни стану кожної функції.
- Надай інформацію про використовувані шаблони Solidity і DeFi.
- Напиши позитивні та негативні аксіоми, ґрунтуючись на інформації про систему.
- Перелічи способи оптимізації та зміни коду для підвищення його надійності (із фрагментами коду).
- Перерахуй приховані методи скаму, що використовуються в коді (з фрагментами коду).
Порада: Візуальне представлення даних часто дає чіткіше розуміння роботи системи. Під час роботи з ChatGPT рекомендується запитувати візуалізацію вихідних даних, наприклад, модифікації станів у вигляді діаграм символів ASCII. Хоча не всі візуалізації можуть мати сенс, деякі з них можуть дати дуже цінне уявлення про роботу смарт-контракту.
По суті, хоча ChatGPT не може замінити людину-аудитора, він істотно доповнює процес аудиту, забезпечуючи більш чітке розуміння переходів між станами протоколу, обмежень, інваріантів і сумісності. Цей інструмент особливо ефективний для розуміння переходів стану протоколу та обмежень.
Порада: Перед початком аудиту надання чату документації щодо протоколу, що перевіряється, може значно підвищити точність і релевантність відповідей. Досить просто згадати: "Це документація, що забезпечує найкращий контекст для "назва_протоколу", який я перевіряю", - і вставити документ.
Можна сказати, що ChatGPT є потужним помічником для аудиторів, забезпечуючи структурований і глибокий підхід до аудиту смарт-контрактів. Однак, варто враховувати, що ChatGTP (і йому подібні сервіси) є лише складними інтерпретаціями машинного аналізу, що працює з імовірностями, тому часто видає помилки та неточності. Відповідно, повністю покладатися на результат ChatGPT не можна - це лише хороший інструмент у правильних руках і "відправна точка" в дослідженні смарт-контракту.
Тому, щоб убезпечити себе від можливих ризиків, необхідно більш ретельніше вивчати смарт-контракти на предмет можливих вразливостей і шахрайських схем.
Як провести поглиблений аудит смарт-контракту? ТОП-100 запитів до ChatGPT
Вище ми розглянули загальний запит (prompt) до ChatGPT, з якого можна почати аналіз смарт-контракту. Але, зрозуміло, детальний аналіз не обмежується вступним запитом.
Шахраї постійно вдосконалюють свою тактику, тому необхідно бути поінформованим і проявляти обережність у багатьох аспектах - це найважливіші стратегії захисту ваших інвестицій у токени.
Давайте розглянемо список ТОП-100 запитів, які дадуть вам змогу професійно підійти до аудиту смарт-контракту:
- Чи успішно компілюється код?
- Яка версія Solidity використовується в коді? Це актуальна стабільна версія?
- Чи присутні зрозумілі коментарі, що пояснюють призначення функцій і змінних?
- Чи використовується в контракті схема "Ownable"? Якщо так, то для яких функцій?
- Чи коректно розподілено змінні стану (state variables) за допомогою за допомогою модифікаторів видимості?
- Чи використовуються події (events) для правильного логування?
- Чи надаються зручні для користувача повідомлення про помилки?
- Чи перевіряється повернуте значення низькорівневих викликів (low-level calls)?
- Чи існують сценарії, в яких власник може авторизувати себе, що може призвести до rug-pulling?
- Хто має контроль над привілейованими обліковими записами та які є механізми контролю?
- Які механізми управління (governance mechanisms) існують у контракті, і чи є управління повністю відкритим або обмеженим?
- Чи використовуються в системі інші контракти і які ролі вони виконують (наприклад, proxy-контракт)?
- Чи існує механізм блокування за часом, і чи можна його обійти?
- Чи існує адекватна документація?
- Чи існують у коді потенційні вразливості до атак DoS або реентерабельності (reentrancy)?
- Усі функції є внутрішніми (internal), за винятком тих, які явно мають бути загальнодоступними/зовнішніми (public/external)?
- У математичних операціях немає арифметичних переповнень/недоповнень (overflows/underflows)?
- Чи використовується безпечна бібліотека OpenZeppelin?
- Ефір або токени не можуть бути випадково надіслані нуль-адресою (0x0)?
- Умови перевіряються за допомогою require перед операціями та зміною стану?
- Стан (state) встановлюється до і під час виконання дій?
- Чи використовується захист від атак повторного входу (reentry) (A викликає B викликає A)?
- Чи правильно реалізовано інтерфейс ERC20?
- Чи використовується модифікатор у кількох місцях тільки, якщо це дійсно необхідно?
- Усі типи задаються явно (наприклад, використовується uint256 замість uint)?
- Усі методи та цикли перебувають у межах максимально допустимого ліміту газу?
- У конструкторі відсутні зайві ініціалізації (пам'ятаєте, що значення за замовчуванням задані)?
- Наявне повне покриття тестами: тестується кожен метод смарт-контракту і всі можливі типи вхідних даних?
- Проведено fuzz-тестування з використанням випадкових входів?
- Чи протестовано всі можливі стани, у яких може перебувати контракт?
- Суми ефіру і токенів за замовчуванням вказуються в одиницях wei?
- Блок/час закінчення краудсейлу (crowdsale) настає після блоку/часу початку (start / enable trading)?
- Курс обміну/конвертації токенів краудсейлу встановлено коректно?
- Чи встановлено м'який/жорсткий ліміт краудсейлу?
- Мінімальний/максимальний допустимий внесок у краудсейл встановлений і протестований?
- Функціональність білих списків краудсейлу протестована?
- Перевірена логіка повернення коштів із краудсейлу?
- Учасники краудсейлу отримують пропорційну кількість токенів чи можуть заявити про свій внесок?
- Чи правильно налаштована тривалість кожного етапу краудсейлу (наприклад, передпродаж, публічний продаж)?
- Чи вказано, які функції мають контролюватися тільки власником (наприклад, припинення краудсейлу, перехід на іншу стадію краудсейлу, включення розподілу токенів краудсейлу, включення розподілу токенів тощо)?
- Логіка наділення краудсейла правами (vesting) перевірена?
- Краудсейл має режим відмовостійкості, який у разі ввімкнення власником обмежує виклики функції та вмикає функцію повернення коштів?
- У краудсейлі передбачена функція відкату, якщо вона має розумний сенс.
- Імпортовані бібліотеки було попередньо перевірено, вони не містять небажаних частин, які можуть бути замінені в майбутніх версіях і можуть бути використані для шкідливих цілей?
- Методи передачі токенів (transfer) обгорнуті в require?
- Чи коректно використовуються require і assert? Метод assert використовується тільки для того, що ніколи не повинно відбуватися, зазвичай він використовується для перевірки стану після внесення змін.
- Чи існує захист від атак рекурсивних викликів (recursive call)?
- Чи обмежуються довжини довільних рядків на вході?
- По можливості уникається використання масивів (array) і замість них маппінги (mappings)?
- Чи не використовуються хеші блоків для роботи з випадковими величинами (майнери можуть впливати на це)?
- Ніде не використовує tx.origin?
- Елементи масиву зсуваються вниз під час видалення елемента, щоб не залишати пропусків?
- Чи використовується revert замість throw?
- Функції негайно завершуються, якщо умови не виконуються?
- Чи усунуто попередження (warnings) компілятора?
- Чи використовується бібліотека SafeMath під час обчислень?
- Чи зчитуються якісь слоти пам'яті (storage slots) кілька разів?
- Чи використовуються якісь необмежені цикли/масиви, які можуть викликати DoS?
- Чи використовується block.timestamp тільки для довгих інтервалів?
- Чи не використовується block.number для розрахунку минулого часу?
- Чи уникається виклик delegatecall, особливо для зовнішніх (нехай навіть і довірених) контрактів?
- Чи не оновлюється довжина масиву під час ітерації по ньому?
- Чи захищені підписи від повторного відтворення за допомогою nonce і block.chainid?
- Переконайтеся, що всі підписи використовують EIP-712?
- Висновок abi.encodePacked() не повинен хешуватися, якщо використовується більше 2 динамічних типів. У загальному випадку краще використовувати abi.encode().
- Уважно перевіряйте assembly-вставки коду.
- Уникайте недостатньої витрати газу (gas griefing).
- Чи є всі приватні дані дійсно приватними?
- Оновлення структури/масиву в пам'яті (memory) не змінить його в сховищі (stage)?
- Чи затінюються (overshadow) змінні стану (stage variables)?
- Обчислення значення змінної на льоту дешевше, ніж його зберігання?
- Чи всі змінні стану зчитуються з правильного контракту (майстер проти клона)?
- Чи правильно використовуються оператори порівняння (>, <, >=, <=), особливо для запобігання помилок off-by-one?
- Чи правильно використовуються логічні оператори (==, !=, &&, ||, !), особливо для запобігання помилок off-by-one?
- Чи завжди множення виконується перед діленням (якщо тільки множення не може переповнитися)?
- Чи замінюються магічні числа (magic numbers) константою з інтуїтивно зрозумілим ім'ям?
- Якщо в одержувача ETH є зворотна (fallback) функція, яка може бути бути скасована (reverted), то чи може це призвести до DoS?
- Чи використовується стандарт SafeERC20 і чи перевіряються значення, що повертаються значення безпечним способом?
- Чи передбачається, що відправник msg.sender завжди є релевантним користувачем?
- Чи не використовується tx.origin для авторизації?
- Чи не використовується address.transfer() або address.send() замість .call.value()?
- При використанні низькорівневих викликів (low-level calls) переконайтеся, що контракт існує до виклику.
- Чи використовується assembly-код для доступу до chainid або коду/розміру/хешу контракту замість синтаксису Solidity?
- Чи використовується ключове слово delete під час встановлення змінної в нульове значення (0, false, "" тощо)?
- Вирази, що передаються логічним операторам/порівнянням (&&/||/>=/==/etc), не повинні мати побічних ефектів.
- Під час роботи з кількома адресами запитайте себе, що станеться, якщо вони будуть однаковими?
- Наскільки добре документований код? Чи наводяться коментарі та приклади скрізь, де використовується нестандартний код?
- Якщо використовується External Call, переконайтеся, чи дійсно необхідний виклик зовнішнього контракту?
- Чи перевіряється результат External Call і чи обробляються помилки?
- Що станеться, якщо під час External Call буде використано весь наданий газ?
- Якщо External Call викликає певну функцію, переконайтеся, що функція реально існує (фантомні функції).
- Переконайтеся, що в модифікаторах (modifiers) не використовуються зовнішні виклики (external calls)
- Чи видаються події (event) для кожної функції, що змінює сховище (storage)?
- Перевірте свої припущення про те, що роблять і повертають зовнішні контракти, які використовуються в основному.
- Слідкуйте за токенами, в яких використовується занадто багато або занадто мало десяткових дробів. Переконайтеся, що максимальне і мінімальне підтримувані значення документовані.
- Чи документовані повноваження, пов'язані з ролями?
- Які ризики при порушенні прав доступу і як це може вплинути на різні компоненти системи?
- Чи може власник маніпулювати токенами і ETH у рамках контракту?
- Як встановлюється адреса оракула (Oracle) і який процес за цим стоїть? Чи існують запасні оракули для підстраховки?
- Як в інших проєктах реалізовано аналогічні функції, чи враховувалися найкращі практики?
Цей чек-лист допоможе вам забезпечити проведення ретельного аудиту безпеки смарт-контрактів Solidity. Він охоплює широкий спектр критичних аспектів для виявлення та пом'якшення потенційних вразливостей і ризиків у коді та пов'язаних із ним системах.
Сподіваємося, що ці приклади допомогли Вам краще розібратися з методикою аудиту смарт-контрактів.
Оскільки вся інформація в блокчейні відкрита (звісно, за умови верифікованого вихідного коду контракту), то озброївшись цими знаннями Ви можете самостійно вивчати смарт-контракти і виявляти різні схеми скаму.
Однак, ми все вже зробили за Вас! Підключайте преміум підписку та відкрийте для себе доступ до ексклюзивних фільтрів за функціями смарт-контрактів та свіжу аналітику. Підвищіть шанси на успішні інвестиції в прибуткові токени.
З повагою, команда Lotus Market.
All posts