Аудит безопасности смарт-контрактов

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Аудит безопасности смарт-контрактов
Сложная
~5 рабочих дней
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1056
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Аудит безопасности смарт-контрактов

Смарт-контракт — это immutable код, управляющий реальными деньгами. Одна ошибка в логике, некорректная проверка доступа или непредвиденная последовательность вызовов могут привести к потере средств пользователей без возможности отката. В 2023-2024 годах совокупные потери от эксплойтов смарт-контрактов составили более $2 млрд. Аудит — не формальность и не страховка: это единственный систематический способ обнаружить уязвимости до того, как это сделают атакующие.

Что происходит во время аудита

Аудит — это не просто запуск автоматических инструментов. Это комбинация ручного анализа, автоматизации и моделирования угроз, специфичных для данного протокола. Слепое доверие к инструментальным отчётам даёт ложное чувство безопасности.

Ручной анализ кода

Аудитор читает код как злоумышленник. Ключевые вопросы для каждой функции: может ли вызывающий получить средства не своё? может ли повторный вызов дать больший результат? изменятся ли инварианты системы?

Проверка access control: каждая write-функция должна иметь явный контроль доступа. onlyOwner, onlyRole, проверка msg.sender. Частая ошибка — забытая проверка в initialize функции upgradeable контракта.

Проверка инвариантов: для каждого контракта формулируются инварианты — свойства, которые должны оставаться истинными всегда. Например: «сумма балансов всех пользователей ≤ totalSupply». Аудитор проверяет, можно ли нарушить каждый инвариант.

Автоматизированный анализ

Slither (Trail of Bits) — статический анализатор для Solidity. Запускается быстро, ловит паттерны типичных уязвимостей:

slither . --config-file slither.config.json \
  --exclude naming-convention,solc-version \
  --print human-summary

Slither детектирует: reentrancy через различные паттерны, неинициализированные переменные в proxy контрактах, небезопасные вызовы delegatecall, арифметические переполнения (хотя Solidity 0.8.x добавил встроенные checks), shadowed переменные.

Mythril — символическое исполнение. Анализирует все возможные пути выполнения. Медленнее Slither, но ловит более сложные паттерны:

myth analyze --solc-json mythril.json contracts/Protocol.sol \
  --execution-timeout 120 \
  --max-depth 22

Echidna — фаззер для свойственного тестирования (property-based testing). Вы описываете инварианты как Solidity функции, Echidna генерирует миллионы случайных транзакций пытаясь нарушить их:

// Echidna invariant: totalSupply никогда не превышает MAX_SUPPLY
function echidna_total_supply_bound() public view returns (bool) {
    return token.totalSupply() <= token.MAX_SUPPLY();
}

Foundry invariant testing — интегрирован в Foundry, аналогичный подход:

// test/invariants/InvariantTest.sol
contract InvariantTest is Test {
    function invariant_solvency() public {
        assertLe(
            vault.totalDebt(),
            vault.totalAssets(),
            "Vault insolvent"
        );
    }
}

Fork тестирование

Для протоколов, взаимодействующих с существующими DeFi примитивами (Uniswap, Aave, Compound), аудит включает fork testing на mainnet snapshot. Это позволяет тестировать реальные взаимодействия с реальным состоянием протоколов.

# Foundry fork test
forge test --fork-url https://eth-mainnet.g.alchemy.com/v2/KEY \
  --fork-block-number 19000000 \
  -vvv --match-contract AttackSimulation

Классификация уязвимостей

Critical: прямая потеря средств

Reentrancy: классическая атака. Контракт вызывает внешний адрес до обновления состояния. Атакующий контракт при получении ETH повторно вызывает уязвимую функцию.

// Уязвимый код
function withdraw(uint256 amount) external {
    require(balances[msg.sender] >= amount);
    (bool success,) = msg.sender.call{value: amount}(""); // вызов внешнего кода
    require(success);
    balances[msg.sender] -= amount; // обновление состояния ПОСЛЕ вызова
}

// Правильно: Checks-Effects-Interactions паттерн
function withdraw(uint256 amount) external nonReentrant {
    require(balances[msg.sender] >= amount);
    balances[msg.sender] -= amount; // сначала обновить состояние
    (bool success,) = msg.sender.call{value: amount}("");
    require(success);
}

The DAO hack (2016, $60M), Lendf.Me (2020, $25M), множество других — reentrancy. nonReentrant modifier от OpenZeppelin и CEI паттерн — стандарт. Нет оправданий не использовать.

Price oracle manipulation: протокол использует spot price из AMM пула как oracle. Атакующий через flash loan манипулирует ценой в пуле, занимает или ликвидирует по искусственной цене.

Защита: TWAP (Time-Weighted Average Price) вместо spot price. Uniswap v3 TWAP, Chainlink — приемлемые оракулы. Spot price из пула — нет.

Logic errors в финансовых расчётах: неправильный порядок операций при целочисленном делении, некорректный учёт decimals разных токенов, рounding в пользу пользователя (не протокола) — накопленные ошибки.

High: значительный ущерб при определённых условиях

Access control bypass: обход проверок через неочевидные пути. Пример: initialize() в upgradeable контракте вызывается без initializer модификатора — можно переинициализировать с другим owner.

Front-running: атакующий видит транзакцию в mempool и вставляет свою перед ней. Классика: DEX slippage атаки, обход deadline проверок.

Flash loan price manipulation: описано выше, но более широкая категория — любые манипуляции через временный капитал.

Unchecked return values: token.transfer() для non-standard ERC20 (USDT) возвращает bool. Если не проверить — silent failure.

// Опасно
token.transfer(recipient, amount);

// Правильно
require(token.transfer(recipient, amount), "Transfer failed");
// или использовать SafeERC20:
token.safeTransfer(recipient, amount);

Medium: ограниченный ущерб или требующие специфических условий

Denial of Service: gas griefing через большие массивы, блокировка через revert в callback, unbounded loops.

Timestamp dependence: использование block.timestamp для критической логики. Валидатор может манипулировать timestamp в пределах ~15 секунд.

Integer overflow/underflow: в Solidity < 0.8.0 без SafeMath. В 0.8.x встроенные checks, но unchecked {} блоки могут снова создать проблему.

Low и Informational

Стилистические проблемы, потенциальные оптимизации, несоответствие документации коду, отсутствие событий для важных операций.

Специфика аудита upgradeable контрактов

Proxy паттерны (TransparentProxy, UUPS, Beacon) добавляют дополнительный attack surface:

Storage collision: proxy и implementation используют одно storage пространство. Если layout не совпадает — переменные перезаписываются.

// OpenZeppelin рекомендует использовать ERC-7201 namespace pattern:
// keccak256(abi.encode(uint256(keccak256("myprotocol.main")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant MAIN_STORAGE_LOCATION = 0x...;

struct MainStorage {
    uint256 totalSupply;
    mapping(address => uint256) balances;
}

function _getMainStorage() private pure returns (MainStorage storage $) {
    assembly { $.slot := MAIN_STORAGE_LOCATION }
}

Uninitialized implementation: прямой вызов initialize() на implementation контракте (не через proxy) может скомпрометировать систему. Решение: _disableInitializers() в constructor implementation.

UUPS: отсутствие upgrade функции в новой реализации: если задеплоить implementation без upgradeTo — контракт навсегда теряет возможность обновления.

Типичная программа аудита

Подготовка: финальная версия кода (feature freeze), документация архитектуры, описание threat model, тест-кейсы. Без финального кода аудит бессмысленен — изменения после аудита не покрываются.

Автоматизированный анализ (день 1-2): Slither, Mythril, Echidna — сбор автоматических findings, исключение false positives.

Ручной анализ (день 3-12): систематический просмотр кода, моделирование атак, проверка инвариантов, бизнес-логика.

Тестирование (день 8-14, параллельно): PoC эксплойты для найденных уязвимостей, fork testing взаимодействий.

Отчёт и remediation (день 14-20): подробный отчёт с severity, PoC, рекомендациями. Команда исправляет, аудитор проверяет fix'ы.

Fix Review (3-5 дней): верификация что исправления не вводят новых уязвимостей.

Тип протокола Объём кода Срок аудита
Простой ERC-20 + vesting < 500 строк 1-2 недели
DeFi протокол (lending/AMM) 1000-3000 строк 3-5 недель
Комплексный протокол с proxy 3000-10000 строк 5-8 недель
Cross-chain мосты любой объём 6-12 недель

Что аудит не гарантирует

Аудит снижает риск, но не устраняет его полностью. Аудиторы — люди, они пропускают баги. Самые известные эксплойты: Euler Finance ($197M, 2023), Nomad Bridge ($190M, 2022), Wormhole ($320M, 2022) — все проходили аудиты.

Правильная стратегия: аудит + bug bounty (Immunefi, HackerOne) + постепенный rollout с лимитами TVL + monitoring (Forta, OpenZeppelin Defender).

Аудит — необходимое, но не достаточное условие безопасности.