Security Ru

Иллюзия случайности: Почему ваш RNG сломают за 1 блок

Иллюзия случайности: Почему ваш RNG сломают за 1 блок

Блокчейн — это детерминированная система. Каждый узел сети, воспроизводя историю транзакций, должен прийти к одному и тому же состоянию. Случайность (энтропия) противоречит самой сути детерминизма.
Разработчики GameFi и NFT-проектов часто игнорируют этот фундамент. Они пытаются получить случайное число инструментами самого блокчейна, создавая уязвимости, которые эксплуатируются майнерами и валидаторами.
1. Нативный рандом: Ловушка для новичка Самый распространенный и опасный паттерн — использование глобальных переменных блока в качестве источника энтропии.
Типичный уязвимый код:
uint256 random = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender))) % 100;
Разберем, почему это не работает.
  • block.timestamp: Валидатор, создающий блок, контролирует время его метки. В Ethereum допустим люфт во времени (обычно до 15 секунд относительно реального). Если на кону джекпот в 10 ETH, валидатор будет перебирать значения timestamp, пока формула не выдаст выигрышное число. Он гарантированно выиграет, так как сам «печатает» выигрышный билет.
  • blockhash: Хеш текущего блока неизвестен в момент выполнения транзакции (он вычисляется после). Использование хеша прошлого блока (blockhash(block.number - 1)) также небезопасно: атакующий может произвести атаку отката (reorg) или просто не публиковать блок, если результат его не устраивает (в случае майнинга).
2. Экономика атаки Многие считают, что майнеру «лень» или «невыгодно» манипулировать блоком ради мелкого выигрыша. Это ошибка.
В эпоху MEV (Maximal Extractable Value) этот процесс автоматизирован. Поисковики (Searchers) и билдеры блоков сканируют мемпул на наличие транзакций с уязвимым рандомом. Если потенциальная прибыль от манипуляции превышает награду за блок (или стоимость газа), атака произойдет мгновенно и автоматически. Безопасность вашего контракта не должна зависеть от «честности» майнеров.
3. The Merge и PREVRANDAO С переходом Ethereum на Proof-of-Stake поле block.difficulty было заменено на block.prevrandao. Некоторые разработчики ошибочно считают его источником «истинной» случайности.
Хотя prevrandao сложнее манипулировать, чем difficulty, он все еще поддается влиянию валидатора (biasability). Валидатор может выбрать — публиковать блок или пропустить слот, тем самым влияя на итоговое значение рандома в цепочке. Для приложений с высокой ценностью (High Value) это недопустимый риск.
4. Решение: Оракулы (Chainlink VRF) Единственный способ получить доказуемо честное случайное число — вынести генерацию за пределы блокчейна (off-chain) с последующей верификацией внутри (on-chain).
Стандарт индустрии — Chainlink VRF (Verifiable Random Function).
  1. Запрос: Смарт-контракт отправляет запрос оракулу (seed + fee).
  2. Генерация: Оракул генерирует число и криптографическое доказательство того, что число получено корректно из seed'а.
  3. Верификация: Смарт-контракт проверяет доказательство. Если оно верно, число принимается.
Никто (включая оракула и майнеров) не может подтасовать результат, так как доказательство математически связано с публичным ключом оракула.
5. Commit-Reveal (Альтернатива) Если бюджет не позволяет использовать оракулы (VRF стоит газа), используйте схему Commit-Reveal.
  1. Участники отправляют хеш своего числа (соль + число).
  2. После окончания приема ставок участники раскрывают исходные числа.
  3. Итоговый рандом вычисляется из комбинации всех чисел. Минус схемы: участник может отказаться раскрывать число, если видит, что проигрывает, тем самым блокируя игру.
Вывод Внутри EVM случайности нет. Любая попытка сгенерировать рандом силами самого контракта (timestamp, blockhash, msg.sender) — это дыра в безопасности. Используйте Chainlink VRF для критически важных механик.
Экономия на оракуле сегодня гарантирует потерю всего банка завтра.