Безопасность

Как проверить EIP-712 подпись перед подтверждением в кошельке

Практическая проверка EIP-712: домен, сеть, verifyingContract, spender, токен, сумма, nonce и deadline, а также признаки опасной подписи.

Как проверить EIP-712 подпись перед подтверждением в кошельке

EIP-712 превращает непрозрачный набор байтов в типизированные поля, которые кошелёк может показать человеку. Такая подпись часто используется для входа, размещения ордера, голосования, разрешения на токены и выполнения операции через relayer. Она не отправляет обычную on-chain транзакцию в момент подтверждения, но её последствия могут быть финансовыми.

Безопасная проверка строится не вокруг названия сайта, а вокруг того, что именно подписывается: для какой сети, какого verifying contract, какого действия, актива, получателя, суммы и срока. Если кошелёк скрывает эти поля или показывает только хеш, смысл подписи нельзя считать проверенным.

Чем EIP-712 отличается от транзакции

Транзакция Ethereum содержит получателя, value, calldata, gas и nonce отправителя, а после отправки попадает в сеть. EIP-712 создаёт подпись структурированного сообщения вне блокчейна. Эту подпись позднее может проверить смарт-контракт, сервер или другой участник.

Подписывающий обычно не платит gas в момент подписи. Это не делает действие безвредным. Если сообщение является Permit, торговым ордером или авторизацией, другой адрес может передать его контракту и изменить состояние. Общее различие между сообщением и транзакцией подробно разобрано в материале о подписи в криптокошельке.

Из каких частей состоит EIP-712

Сообщение включает описание типов, основной тип, домен и конкретные значения. Стандарт строит хеш структуры и соединяет его с domain separator. Кошелёк подписывает итоговый хеш приватным ключом, а проверяющая сторона восстанавливает адрес подписанта.

Домен отделяет подпись одного приложения и контракта от другого. В нём могут присутствовать:

  • name – название домена, которое задал разработчик;
  • version – версия схемы;
  • chainId – идентификатор сети;
  • verifyingContract – контракт, который должен принять подпись;
  • salt – дополнительный разделитель.

Сам EIP-712 не добавляет универсальную защиту от повторного применения. Безопасность replay зависит от полей конкретного сообщения, например nonce, deadline, chainId и логики verifying contract.

Проверка перед подписью

  1. Остановитесь и определите ожидаемое действие. Если вы нажали «войти», но кошелёк показывает Permit, Permit2, Order, Transfer или Delegation, запрос не соответствует цели.
  2. Проверьте активную сеть и chainId. Они должны совпадать с сетью приложения. Значение 0 или отсутствие понятной привязки повышает риск повторного использования в другой сети, если контракт не добавляет собственную защиту.
  3. Проверьте verifyingContract. Сравнивать нужно полный адрес с контрактом, который действительно использует приложение. Название домена легко скопировать, адрес – фактическая граница проверки.
  4. Найдите основной тип сообщения. Permit, PermitSingle, PermitBatch, Order, Vote и Login означают разные полномочия. Красивое описание интерфейса не заменяет тип.
  5. Проверьте адрес получателя прав. Поле может называться spender, operator, delegate, recipient или executor. Неизвестный адрес нельзя считать безопасным только потому, что запрос появился на знакомой странице.
  6. Проверьте актив и сумму. Убедитесь, что token или asset соответствует выбранному токену. Безлимитное значение фактически даёт доступ ко всему текущему и будущему балансу в пределах разрешения.
  7. Проверьте nonce. Он должен предотвращать повторное применение уже использованной подписи. Не нужно угадывать правильное число, но отсутствие nonce в финансовой авторизации требует объяснимой защиты в контракте.
  8. Проверьте deadline или expiry. Слишком далёкий срок увеличивает окно атаки. Нулевое или максимальное значение может означать отсутствие практического ограничения.
  9. Проверьте дополнительные условия. Для ордера это цена, объём, сторона сделки, получатель и комиссия. Для голосования – proposal и choice. Для сессии – методы, лимиты и разрешённые контракты.
  10. Подтверждайте только при полном совпадении. Если хотя бы одно критичное поле непонятно, отклоните запрос, закройте вкладку и заново откройте сервис из сохранённого адреса.

Как проверить контракт без доверия к интерфейсу

Скопируйте verifyingContract из окна кошелька и найдите его во встроенном обозревателе сети или в обозревателе, которому вы доверяете. Проверьте, верифицирован ли код, как называется контракт, является ли адрес proxy и кто может обновлять реализацию. Совпадение первых и последних символов недостаточно – вредоносный адрес может выглядеть похоже.

Если приложение публикует адреса в собственной документации, открывайте её независимо, а не по ссылке из подозрительного сообщения. Для proxy важно проверять не только оболочку, но и текущую implementation. Даже официально развёрнутый контракт может иметь широкие возможности, поэтому назначение метода всё равно нужно понимать.

Permit, Permit2 и токенные разрешения

ERC-2612 Permit позволяет владельцу токена подписать allowance для spender. Контракт токена проверяет подпись и устанавливает разрешение без отдельной approve-транзакции владельца. Критические поля – owner, spender, value, nonce и deadline.

Permit2 использует отдельный универсальный контракт и может управлять разрешениями для многих токенов. В сообщении встречаются token, amount, expiration, nonce, spender и sigDeadline. Подробная механика описана в разборе Permit и Permit2. Опаснее всего сочетание неизвестного spender, большой суммы и долгого срока.

После использования подписи on-chain разрешение может продолжать действовать. Отключение сайта от кошелька его не отзывает. Нужно отдельно уменьшить allowance или использовать функцию отмены, если она предусмотрена контрактом.

Признаки опасного запроса

  • Сайт обещает airdrop или срочное спасение средств и торопит подписать сообщение.
  • Кошелёк не декодирует поля и показывает слепую подпись или неизвестный хеш.
  • Название домена знакомое, но verifyingContract не совпадает с ожидаемым.
  • Запрос на вход содержит spender, token, amount, operator или transfer details.
  • Сумма максимальная, срок не ограничен, а получатель прав неизвестен.
  • Одно действие вызывает несколько разных подписей без понятного объяснения.
  • Домен открыт из рекламного объявления, личного сообщения или похожего адреса.

Так работают многие crypto drainer: они не обязаны красть seed-фразу, если пользователь сам выдаёт действительное разрешение. Антивирус и аппаратный кошелёк не исправят смысл уже подтверждённой подписи.

Если кошелёк показывает не все поля

Не переносите запрос в другой кошелёк только ради кнопки подтверждения. Отсутствие декодирования означает, что интерфейс не даёт достаточно информации. Для значимой суммы безопаснее отказаться и проверить действие на отдельном адресе с минимальным балансом.

Аппаратный кошелёк может подтвердить криптографическую подпись, но маленький экран не всегда показывает всю структуру. Если устройство сообщает blind signing, пользователь фактически доверяет компьютеру подготовить корректные данные. Для EIP-712 это особенно опасно, поскольку одна подпись может стать исполнимым разрешением.

Что делать после случайной подписи

Сначала отключите подозрительное приложение, но не считайте это отзывом полномочий. Проверьте allowance и operator approvals в затронутой сети, отмените их и изучите историю адреса. Если подпись могла создать ордер, Permit или сессию, используйте предусмотренный протоколом cancel, invalidate nonce или revoke.

При признаках активного вывода перенесите оставшиеся активы на новый адрес с чистого устройства. Не отправляйте дополнительный gas на потенциально скомпрометированный адрес без плана: автоматический бот может забрать его. Сессионные разрешения и их ограничения разобраны отдельно в материале о сессионных ключах dapp.

Короткий контрольный список

  • Действие совпадает с тем, что вы начали в приложении.
  • Сеть и chainId верны.
  • Полный verifyingContract проверен независимо.
  • Primary type понятен.
  • Spender, operator или recipient ожидаемы.
  • Токен, сумма и направление операции верны.
  • Nonce присутствует там, где подпись должна быть одноразовой.
  • Deadline разумно ограничен.
  • Кошелёк показывает структуру без blind signing.

Итог

EIP-712 улучшает читаемость подписи, но не определяет, безопасно ли её содержание. Проверять нужно домен, chainId, verifyingContract и все поля действия. Особенно опасны неизвестный spender, безлимитная сумма, долгий срок и подпись, не соответствующая ожидаемой операции. Если кошелёк не позволяет понять смысл сообщения, правильное действие – отклонить запрос.