Ми щойно побачили, як маленька лазівка призводить до фінансових збитків (різної величини), подібним чином розумні контракти, розроблені за допомогою Solidity, схильні до різних відомих і невідомих атак. Експлуатанти використовують переваги помилок та лазівок, щоб зазирнути у смарт -контракти та маніпулювати ними для здійснення атак. Тут ми представляємо вичерпний список 5 найпоширеніших помилок у мові програмування Solidity.
У QuillAudits ми дотримуємось адаптивної методології, щоб зрозуміти суть кожного злому та реалізувати свої знання щодо майбутніх смарт -контрактів, щоб уникнути будь -якої потенційної загрози.
Помилки в твердій мові програмування
1. Не позначений зовнішній дзвінок
Ми в першу чергу розглядаємо це питання, оскільки це одна з найбільш часто зустрічаються підводних каменів. Як правило, надсилання ефіру на будь-який зовнішній рахунок здійснюється через передача () функція. Окрім цього, дві найбільш широко використовувані функції для здійснення зовнішнього дзвінка: виклик () та send (), тут головним чином виклик () Ця функція широко використовується для виконання різнобічних зовнішніх викликів розробниками.
Хоча це виклик () та send () Функції повертають логічне значення, яке вказує, був виклик успішним чи ні. Таким чином у цьому випадку, якщо є якась із функцій виклик () or send () не вдається виконати завдання, вони повертаються за допомогою помилковий. Отже, якщо розробник не перевірить повернене значення, це стане підводним каменем.
Уразливість
Розглянемо приклад нижче:
контрактне лото {
boolpublic payedOut = false;
звертатися до публічного переможця;
uintpublic winAmount;
//… тут є додаткові можливості
функція sendToWinner () public {
вимагати (! payedOut);
winner.send (winAmount);
payedOut = істина;
}
функція removewLeftOver () public {
вимагати (payedOut);
msg.sender.send (this.balance);
}
}
У вищезазначеному лото-контракті ми можемо помітити, що a переможець отримує winAmount ефіру, залишаючи трохи залишків для вилучення з будь-якого зовнішнього агента.
Тут підводний камінь існує у рядку [11], де a послати використовується без перехресної перевірки відповіді. У наведеному вище прикладі a переможець транзакція якого не вдається (або через дефіцит газу, або якщо це контракт, який навмисно вводить резервну функцію), дозволяє виплачено для встановлення правда незалежно від того, була транзакція ефіру успішною чи ні. У цьому випадку будь-який експлуататор може вилучити переможця виграш через знятиLeftOver функції.
Підхід QuillAudit
Наша внутрішня команда розробників вирішує цю помилку за допомогою [передача] функція замість [відправити] функція, оскільки [передача] повернеться, якщо зовнішня транзакція повернеться. А якщо ви використовуєте [надіслати], завжди перевірте повернене значення.
Одним із надійних підходів, якого ми дотримуємося, є використання [схеми виведення]. Тут ми логічно ізолюємо зовнішню функціональність надсилання від решти кодової бази і ставимо штам потенційно невдалих транзакцій на кінцевого користувача, оскільки він сам викликає функцію зняття.
2. Повторне входження
Смарт-контракти Ethereum викликають та використовують коди інших зовнішніх контрактів, і для їх виконання контракти повинні подавати зовнішні дзвінки. Ці зовнішні дзвінки є вразливими та схильними до атак; одна така атака мала місце нещодавно у випадку злому DAO.
Уразливість
Зловмисники здійснюють такі атаки, коли за контрактом надсилається ефір за невідомою адресою. У цьому випадку зловмисник може створити контракт за зовнішньою адресою, яка має шкідливий код у резервній функції, і цей шкідливий код буде викликаний, коли контракт надсилає ефір на цю адресу.
Факт: Термін "повторне входження" був винайдений з того факту, що коли зовнішній шкідливий контракт викликає функцію над вразливим контрактом, а потім шлях виконання коду знову "вводить" її.
Розглянемо приклад нижче, це сховище Ethereum, яке дозволяє вкладникам виводити лише 1 ефір на тиждень.
договір EtherStore {
uint256 публічний вивідLimit = 1 ефір;
зіставлення (адреса => uint256) загальнодоступне lastWithdrawTime;
відображення (адреса => uint256) державних балансів;
функція depositFunds () зовнішня сплата {
залишки [msg.sender] += msg.value;
}
функція removewFunds (uint256 _weiToWithdraw) public {
вимагати (залишки [msg.sender]> = _weiToWithdraw);
// обмежити виведення
вимагати (_weiToWithdraw <= removeLimit);
// обмежити час, дозволений для виведення
вимагати (зараз> = lastWithdrawTime [msg.sender] + 1 тиждень);
вимагати (msg.sender.call.value (_weiToWithdraw) ());
баланси [msg.sender] -= _weiToWithdraw;
lastWithdrawTime [msg.sender] = зараз;
}
}
У вищезазначеному контракті ми маємо дві публічні функції: [depositFunds] та [cancelvaFunds]. [DepositFunds] використовується для збільшення залишку відправника, тоді як [curveFunds] визначає суму, яку потрібно зняти. У цьому випадку це буде успіхом, якщо сума, яку потрібно вивести, менше 1 ефіру.
Підводний камінь тут лежить у лінії [17], де відбувається перенесення ефіру. Зловмисник може створити зловмисний контракт з адресою контракту [EtherStores] як єдиним параметром конструктора. Це зробить [etherStore] загальнодоступною змінною, отже, більш схильною до атак.
Підхід QuilllAudit
Ми дотримуємося різних методів, щоб уникнути потенційних вразливих місць, що виникають у смарт-контрактах. Найпершим і найкращим із можливих способів є використання вбудованої функції [передачі] при передачі ефіру до будь-якого зовнішнього контракту.
По-друге, важливо забезпечити, щоб усі логічні зміни у змінних стану були зроблені перед тим, як відправити ефір поза контрактом. У прикладі [EtherStore] рядки [18] та [19] слід поставити перед рядком [17].
Третій прийом також може бути використаний для запобігання повторним дзвінкам; через введення мьютексу. Це додавання змінної стану, яка блокує контракт під час виконання коду.
3. Видимість за замовчуванням
Існують специфікатори видимості для функцій, які ми використовуємо в Solidity, і вони прописують спосіб їх виклику. Саме видимість визначає виклик функцій; зовні користувачі, за іншими похідними контрактами, лише всередині або лише зовні. Давайте розглянемо, як помилкове використання специфікаторів видимості може спричинити величезну вразливість у смарт-контрактах.
Уразливість
За замовчуванням видимість функції є [загальнодоступною], отже, зовнішні користувачі можуть викликати функції без конкретної видимості. Помилка виникає, коли розробники забувають вказати видимість функцій, які повинні бути приватними (або можуть бути викликані в рамках самого контракту). Наприклад;
контракт HashForEther {
функція removewWinnings () {
// Переможець, якщо останні 8 шістнадцяткових символів адреси дорівнюють 0
require (uint32 (msg.sender) == 0);
_sendWinnings ();
}
function _sendWinnings () {
msg.sender.transfer (цей баланс);
}
}
Вищезазначений контракт - це проста гра в головоломки щодо вгадування адрес. У цьому ми бачимо, що видимість функцій не вказана, зокрема функція [_sendWinnings] є [public] (за замовчуванням), отже, її можна викликати через будь-яку адресу для викрадення нагороди.
Підхід QuillAudit
Наша внутрішня команда складається з досвідчених розробників, які завжди дотримуються найкращих практик аудиту, тут видимість функцій повинна бути чітко визначена, навіть якщо вони мають бути відкритими, про це слід згадати.
4. Захист використання конструкторів
Як правило, конструкторами називають спеціальні функції, які використовуються для виконання критичних та привілейованих завдань під час ініціалізації контрактів. До Solidity [v0.4.22] конструктори носили те саме ім'я, що використовувалося в контракті, який їх містив. Тепер розглянемо випадок, коли назва контракту змінюється на етапі розробки, але назва конструктора залишається незмінною, ця лазівка також може забезпечити зловмисникам легкий доступ до вашого смарт-контракту.
Уразливість
Це може призвести до серйозних наслідків, якщо назву контракту змінити, але ім'я конструктора не змінити. Наприклад:
договір OwnerWallet {
адреса державного власника;
// конструктор
функція ownerWallet (адреса _власника) публічна {
власник = _власник;
}
// Відступати. Зберіть ефір.
function () оплачується {}
функція remove () public {
вимагати (msg.sender == власник);
msg.sender.transfer (цей баланс);
}
}
У вищезазначеному контракті ми бачимо, що лише власник може вивести ефір за допомогою виклику функції [зняти]. Тут уразливість виникає, коли конструктор називається інакше, ніж контракт (перший лист інший!). Таким чином, експлуататор може викликати функцію [ownerWallet] і авторизуватися як власник, а потім вивести весь ефір за контрактом, зателефонувавши [зняти].
Підхід QuillAudit
Ми дотримуємось версії [0.4.22] компілятора Solidity. Ця версія представила ключове слово; [конструктор], який вимагає, щоб ім'я функції відповідало імені контракту.
5. Аутентифікація Tx.Origin
Тут [Tx.Origin] - глобальна змінна Solidity, вона містить адресу облікового запису, який первинно здійснив виклик або транзакцію. Цю змінну не можна використовувати для автентифікації, оскільки це робить контракт уразливим до фішингових атак.
Уразливість
Контракти, що дозволяють користувачам через змінну [tx.origin], піддаються зовнішнім атакам, що змушують користувачів виконувати автентифіковані дії щодо помилкового контракту. Розглянемо наведений нижче приклад:
договір Phishable {
адреса державного власника;
конструктор (адреса _власника) {
власник = _власник;
}
function () зовнішня оплата {} // збирати ефір
функція removewAll (адреса _реципієнта) загальнодоступна {
вимагати (tx.origin == власник);
_recipient.transfer (this.balance);
}
}
Тут, у рядку [11], контракт санкціонує функцію [cancelwAll] за допомогою [tx.origin].
Підхід QuillAudit
Зазвичай ми уникаємо використання [tx.origin] для авторизації в смарт-контрактах. Хоча використання [tx.origin] не є суворо забороненим, у ньому є деякі конкретні випадки використання. Ми можемо використовувати [tx.origin], щоб заборонити зовнішнім контрактам викликати поточний контракт, він може бути виконаний з [require] форми [require (tx.origin == msg.sender)]. Це робиться, щоб уникнути виклику проміжних контрактів для виклику поточного контракту, який обмежує контракт звичайними безкодовими адресами.
Остаточне завершення роботи
Ми всебічно висвітлили п’ять загальних підводних каменів у мові Solidity. Розробляючи інтелектуальні контракти, ми не повинні забувати, що вони незмінні за задумом, а це означає, що коли ми їх створюємо, немає можливості виправити вихідний код.
Це ставить перед розробниками великий виклик скористатися перевагами доступних засобів тестування та аудиту безпеки перед розгортанням.
Виявлення потенційних зловмисних загроз для смарт-контрактів та ризиків, деякі з яких ми згадали вище, виконуються нашою власною командою експертів з аудиту дуже унікальним та надійним способом. Ми, QuillAudits, докладаємо максимум зусиль для дослідження безпеки, щоб ваш контракт оновлювався відповідно до всіх практик безпеки програмного забезпечення, щоб ваш контракт був надійним.
Зверніться до QuillHash
Маючи багаторічну присутність у галузі, QuillHash постачає корпоративні рішення по всьому світу. QuillHash з командою експертів - провідна компанія, що розробляє блокчейн, що пропонує різні галузеві рішення, включаючи DeFi Enterprise. Якщо вам потрібна допомога в аудиті смарт-контрактів, не соромтеся звертатися до наших експертів тут!
Підпишіться на QuillHash, щоб отримати додаткові оновлення
Джерело: https://blog.quillhash.com/2021/06/04/top-5-common-errors-in-solidity-programming-language/
- 11
- рахунки
- Перевага
- ВСІ
- аудит
- Authentication
- авторизації
- КРАЩЕ
- blockchain
- Помилка
- помилки
- call
- випадків
- Викликати
- виклик
- код
- загальний
- компанія
- контракт
- контрактів
- Поточний
- DAO
- Defi
- дизайн
- Розробник
- розробників
- розробка
- підприємство
- Ефір
- Ефіріума
- Event
- experts
- фінансовий
- Перший
- стежити
- форма
- Безкоштовна
- функція
- майбутнє
- гра
- ГАЗ
- Глобальний
- великий
- зламати
- тут
- Як
- HTTPS
- величезний
- У тому числі
- промисловість
- IT
- мова
- вести
- провідний
- Лінія
- список
- матч
- Інше
- власник
- пластир
- Викрійки
- phishing
- фішинг-атаки
- призначати
- представити
- приватний
- Програмування
- громадськість
- тягне
- дослідження
- відповідь
- REST
- сейф
- безпеку
- Послуги
- комплект
- простий
- невеликий
- розумний
- розумний контракт
- Спритні контракти
- So
- Софтвер
- солідність
- Рішення
- стан
- успіх
- Тестування
- Джерело
- загрози
- час
- топ
- топ 5
- угода
- Transactions
- us
- користувачі
- значення
- склеп
- видимість
- Уразливості
- вразливість
- Вразливий
- week
- ВООЗ
- в
- років