Паттерны безопасной разработки

Безопасность — это не геройство после взлома, а скучная дисциплина до него.

Паттерн безопасной разработки — устоявшийся приём проектирования, который по умолчанию устраняет целый класс уязвимостей, освобождая от необходимости «не ошибиться вручную».

Сводим воедино

За курс мы вывели набор паттернов; теперь соберём их как рабочую дисциплину. Идея в том, чтобы правильное было путём наименьшего сопротивления: использовать проверенные кирпичи, а не изобретать своё.

Ключевые паттерны

ПаттернЧто устраняет
Checks-Effects-Interactionsреентранси
ReentrancyGuard (nonReentrant)повторный вход (страховка)
Pull-over-pushDoS выплат, реентранси
Контроль доступа (роли, мультисиг)несанкционированный вызов
Оракулы + TWAP/свежестьманипуляция ценой
nonce + EIP-712реплей подписи
Снапшоты прошлого блокафлеш-голосование

Минимизация и проверенные библиотеки

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

Проверенные библиотеки: используйте OpenZeppelin для стандартных кирпичей (ERC-20, Ownable, AccessControl, ReentrancyGuard, Pausable, безопасные обёртки переводов). Эти реализации многократно проаудированы; ваш собственный токен почти наверняка будет содержать тонкую ошибку.

// Собираем из проверенных кирпичей
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract Vault is Ownable, Pausable, ReentrancyGuard {
    function withdraw() external nonReentrant whenNotPaused {
        // CEI внутри...
    }
}

Аварийные механизмы

Даже идеальный код стоит снабдить рубильниками: пауза (Pausable) — остановить операции при инциденте; лимиты на вывод/частоту — ограничить ущерб; мониторинг — заметить аномалию рано. Это не признание слабости, а часть зрелого дизайна: предполагаем, что что-то пойдёт не так, и ограничиваем последствия.

Как работает под капотом: безопасные переводы

Разные токены ведут себя по-разному (некоторые не возвращают bool, некоторые берут комиссию при переводе). OpenZeppelin SafeERC20 унифицирует это и проверяет результат, избавляя от тонких багов интеграции — пример того, как библиотека инкапсулирует знание о граблях.

Частые ошибки

  • Свой ERC-20/контроль доступа «с нуля». Почти гарантированная тонкая ошибка.
  • Лишние функции и привилегии. Раздутая поверхность атаки.
  • Нет паузы/лимитов. Инцидент сразу становится катастрофой.

Итоги

  • Сделайте безопасное путём наименьшего сопротивления: проверенные паттерны вместо самописа.
  • Минимизируйте код и привилегии; применяйте принцип наименьших привилегий.
  • Стройте на OpenZeppelin (включая SafeERC20, Pausable).
  • Закладывайте аварийные рубильники: пауза, лимиты, мониторинг.
Проверьте себя
1. Почему опасно писать свой ERC-20 и контроль доступа «с нуля»?
AЭто медленно компилируется
BВысока вероятность тонкой ошибки; проверенные библиотеки (OpenZeppelin) многократно проаудированы
CЭто запрещено стандартом
DЭто дороже по газу всегда
2. Что означает принцип минимизации?
AМинимум комментариев
BМеньше кода и привилегий — меньше поверхность атаки
CМинимум газа любой ценой
DОдин файл на проект
3. Зачем закладывать паузу и лимиты, если код «идеален»?
AДля красоты
BЧтобы при инциденте ограничить ущерб и успеть среагировать
CЧтобы ускорить транзакции
DЧтобы скрыть владельца