Разработка Bug Bounty программы

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка Bug Bounty программы
Средняя
~3-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

Разработка системы реагирования на инциденты

Hack в DeFi — это не взлом в традиционном смысле. Нет брутфорса, нет фишинга. Атака занимает одну транзакцию (иногда несколько), деньги уходят необратимо за секунды. К моменту когда команда узнаёт об инциденте — ущерб уже нанесён. Единственный способ минимизировать потери — детектировать атаку в реальном времени (в идеале — до исполнения транзакции) и иметь заранее подготовленные механизмы остановки.

Ronin Bridge (март 2022, $625M) не заметили взлом 6 дней. Euler Finance (март 2023, $197M) среагировали быстро, договорились о возврате через 2 недели — нетипичный хэппи-энд. Разница в подходе к incident response.

Архитектура системы реагирования

Система состоит из трёх уровней:

Детекция (мониторинг) — on-chain и off-chain мониторинг аномалий в реальном времени.

Реакция (circuit breaker) — набор on-chain механизмов для немедленной остановки критичных функций.

Коммуникация и восстановление — процессы уведомления, оценки ущерба, координации ответа.

Circuit Breaker контракты

Pause механизм

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";

contract ProtocolCore is Pausable, AccessControl {
    bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

    // Emergency pause: отдельные функции, не весь протокол
    mapping(bytes4 => bool) public functionPaused;

    event FunctionPaused(bytes4 indexed selector, address indexed by);
    event FunctionUnpaused(bytes4 indexed selector);
    event EmergencyWithdrawTriggered(address indexed asset, uint256 amount);

    modifier notFunctionPaused() {
        require(!functionPaused[msg.sig], "Function paused");
        _;
    }

    // Глобальная остановка — только через timelock (кроме Guardian)
    function pause() external {
        require(
            hasRole(PAUSER_ROLE, msg.sender) || hasRole(GUARDIAN_ROLE, msg.sender),
            "Not authorized"
        );
        _pause();
    }

    // Возобновление — только через timelock governance
    function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) {
        _unpause();
    }

    // Точечная пауза конкретной функции
    function pauseFunction(bytes4 selector) external onlyRole(GUARDIAN_ROLE) {
        functionPaused[selector] = true;
        emit FunctionPaused(selector, msg.sender);
    }

    // Критичная функция: вывод средств в safe wallet при компрометации
    function emergencyWithdraw(
        address asset,
        address safeDestination
    ) external onlyRole(GUARDIAN_ROLE) whenPaused {
        require(safeDestination != address(0), "Invalid destination");
        uint256 balance = IERC20(asset).balanceOf(address(this));
        if (balance > 0) {
            IERC20(asset).safeTransfer(safeDestination, balance);
            emit EmergencyWithdrawTriggered(asset, balance);
        }
    }
}

Rate limiter

Не весь DeFi взламывается одной транзакцией. Часто атака — серия транзакций. Rate limiter замедляет отток средств:

contract RateLimiter {
    struct RateLimit {
        uint256 maxAmount;       // максимум за период
        uint256 periodDuration;  // длина периода в секундах
        uint256 currentAmount;   // потрачено в текущем периоде
        uint256 periodStart;     // начало текущего периода
    }

    mapping(address => RateLimit) public limits; // per-asset limits

    event RateLimitExceeded(address indexed asset, uint256 requested, uint256 available);

    function _checkAndUpdateRateLimit(address asset, uint256 amount) internal {
        RateLimit storage limit = limits[asset];
        if (limit.maxAmount == 0) return; // лимит не установлен

        // Сбрасываем период если он истёк
        if (block.timestamp >= limit.periodStart + limit.periodDuration) {
            limit.currentAmount = 0;
            limit.periodStart = block.timestamp;
        }

        uint256 available = limit.maxAmount - limit.currentAmount;
        if (amount > available) {
            emit RateLimitExceeded(asset, amount, available);
            revert("Rate limit exceeded");
        }

        limit.currentAmount += amount;
    }
}

Rate limiter — не панацея: атакующий может дождаться сброса периода. Но он даёт команде время для реакции и снижает максимально возможный единовременный ущерб.

Мониторинговая система

On-chain события как триггеры

Первый уровень детекции — listening к событиям контракта. Аномальные события, которые стоит мониторить:

interface MonitoringRule {
  eventSignature: string;
  condition: (event: Log) => boolean;
  severity: 'low' | 'medium' | 'high' | 'critical';
  action: 'alert' | 'auto-pause' | 'notify-guardian';
}

const rules: MonitoringRule[] = [
  {
    eventSignature: 'Withdrawal(address,uint256)',
    condition: (e) => BigInt(e.data) > LARGE_WITHDRAWAL_THRESHOLD,
    severity: 'high',
    action: 'alert',
  },
  {
    eventSignature: 'FlashLoan(address,uint256)',
    condition: (e) => BigInt(e.data) > FLASH_LOAN_THRESHOLD,
    severity: 'medium',
    action: 'alert',
  },
  {
    eventSignature: 'OwnershipTransferred(address,address)',
    condition: () => true, // любой transfer ownership — critical
    severity: 'critical',
    action: 'notify-guardian',
  },
];

Mempool мониторинг (pre-execution detection)

Наиболее ценная возможность — увидеть атаку до её исполнения. Транзакция в mempool ещё не включена в блок — у команды есть несколько секунд.

import { ethers } from 'ethers';

const provider = new ethers.WebSocketProvider(WS_RPC_URL);

// Подписка на pending транзакции
provider.on('pending', async (txHash) => {
  const tx = await provider.getTransaction(txHash);
  if (!tx) return;

  // Проверяем: является ли это вызовом к нашему контракту
  if (tx.to?.toLowerCase() !== CONTRACT_ADDRESS.toLowerCase()) return;

  // Анализируем calldata
  const decoded = decodeCalldata(tx.data);
  const risk = assessRisk(decoded, tx);

  if (risk.level === 'critical') {
    await triggerEmergencyPause(risk);
    await notifyGuardian(tx, risk);
  }
});

async function triggerEmergencyPause(risk: RiskAssessment): Promise<void> {
  // Отправляем pause транзакцию с высоким gasPrice
  // чтобы она включилась в блок раньше атаки
  const guardianWallet = new ethers.Wallet(GUARDIAN_KEY, provider);
  const gasPrice = await provider.getFeeData();

  await guardianContract.pause({
    maxFeePerGas: gasPrice.maxFeePerGas! * 3n, // 3x от текущего
    maxPriorityFeePerGas: ethers.parseUnits('50', 'gwei'), // высокий tip
  });
}

Проблема: автоматический pause по pending транзакции создаёт риск ложных срабатываний и DoS. Нужна тщательная настройка правил.

Invariant monitoring

Самый надёжный детектор — непрерывная проверка финансовых инвариантов:

interface ProtocolInvariant {
  name: string;
  check: (state: ProtocolState) => boolean;
  description: string;
}

const invariants: ProtocolInvariant[] = [
  {
    name: 'total_supply_consistency',
    check: (s) => s.totalShares * s.pricePerShare <= s.totalAssets * 1.001,
    description: 'Total shares value не превышает total assets',
  },
  {
    name: 'no_sudden_tvl_drop',
    check: (s) => s.currentTVL >= s.previousTVL * 0.8,
    description: 'TVL не упал более чем на 20% за один блок',
  },
  {
    name: 'oracle_price_sanity',
    check: (s) => Math.abs(s.oraclePrice - s.chainlinkPrice) / s.chainlinkPrice < 0.05,
    description: 'Цена oracle не отклоняется более чем на 5% от Chainlink',
  },
];

// Запускается каждый блок
async function checkInvariants(blockNumber: number): Promise<void> {
  const state = await fetchProtocolState(blockNumber);

  for (const invariant of invariants) {
    if (!invariant.check(state)) {
      await triggerAlert({
        level: 'critical',
        invariant: invariant.name,
        description: invariant.description,
        blockNumber,
        state,
      });
    }
  }
}

Инфраструктура мониторинга

Технический стек

Компонент Инструмент Назначение
Event listening Alchemy Webhooks / QuickNode Streams Real-time on-chain события
Mempool watching Blocknative / собственная нода Pre-execution detection
Indexing The Graph / Ponder Исторические данные для аномалий
Alerting PagerDuty + Telegram Bot Уведомления команды
Metrics Prometheus + Grafana Dashboards и trending
Automation Chainlink Automation / Gelato Автоматические действия

Forta Network интеграция

Forta — децентрализованная сеть мониторинга смарт-контрактов. Позволяет деплоить detection bots, которые анализируют каждую транзакцию:

// Forta Detection Bot
import { Finding, FindingSeverity, FindingType, TransactionEvent } from 'forta-agent';

export function handleTransaction(txEvent: TransactionEvent) {
  const findings: Finding[] = [];

  // Проверяем вызовы к нашему контракту
  const calls = txEvent.filterFunction(
    'withdraw(uint256,address)',
    CONTRACT_ADDRESS
  );

  for (const call of calls) {
    const amount = BigInt(call.args.amount);
    if (amount > LARGE_WITHDRAWAL_THRESHOLD) {
      findings.push(
        Finding.fromObject({
          name: 'Large Withdrawal Detected',
          description: `Withdrawal of ${amount} tokens`,
          alertId: 'LARGE-WITHDRAWAL',
          severity: FindingSeverity.High,
          type: FindingType.Suspicious,
        })
      );
    }
  }

  return findings;
}

Forta имеет сеть нод, которые запускают боты — распределённая детекция без единой точки отказа.

Процессы и runbook

Технические компоненты бесполезны без чётких процессов. Runbook — документ «что делать при инциденте»:

T+0 (первый alert):

  • Guardian on-call получает Telegram/PagerDuty алерт
  • Оценка: false positive или реальная атака? Время на оценку: 2-3 минуты максимум
  • Если сомнение — pause немедленно, разбираемся потом

T+5 минут:

  • Pause выполнен (или принято решение не паузить)
  • Уведомление core team
  • Начало on-chain расследования (Tenderly transaction trace)

T+30 минут:

  • Публичное уведомление через Twitter/Discord: «We are investigating an issue»
  • Оценка ущерба
  • Координация с другими протоколами (если атака cross-protocol)

T+2 часа:

  • Детальный post-mortem начат
  • Связь с белыми хакерами/исследователями (если нужна помощь)
  • Обращение в полицию (если юрисдикция позволяет)

T+24-48 часов:

  • Публичный post-mortem
  • Plan восстановления
  • Координация с биржами (заморозка адресов атакующего)

Ключи Guardian и безопасность

Guardian ключ, который может pause протокол — сам по себе уязвимость. Если он скомпрометирован — атакующий паузит протокол и вымогает деньги за разблокировку.

Рекомендации:

  • Guardian — Gnosis Safe 2/3 или 3/5, не EOA
  • Hardware wallet для signing (Ledger/Trezor)
  • Географически распределённые keyholders
  • Регулярные drill-тренировки (раз в квартал)
  • Мониторинг самого Guardian мультисига

Процесс работы

Дизайн (1 неделя). Карта угроз: какие атаки возможны, какие инварианты нарушаются, какие функции критичны. Дизайн circuit breaker архитектуры.

Разработка on-chain компонентов (2 недели). Pause механизм + rate limiter + emergency withdraw + тесты.

Разработка мониторинга (2-3 недели). Event listeners + invariant checks + Forta bot (опционально) + alerting pipeline.

Разработка runbook (3-5 дней). Документация процессов, drill training.

Аудит circuit breaker контрактов (1 неделя). Контракты с pause механизмом — сами по себе attack surface.

Интеграция и тестирование (1 неделя). End-to-end тест: симуляция атаки → детекция → pause → recovery.

Полный цикл: 2-2,5 месяца. Стоимость зависит от размера протокола и уровня автоматизации.