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

При этом сама схема ECDSA, используемая в сетях Bitcoin и Ethereum, не считается взломанной: реальные риски обычно возникают вокруг её реализации и применения.
Давайте разберёмся по шагам. Важно различать несколько вещей, которые часто смешиваются: подпись транзакции в криптокошельке, подпись произвольного сообщения и порядковый номер транзакции в сети. У них разные задачи и разные угрозы. Понимание этой разницы помогает оценить, что именно просит подтвердить кошелёк и какие меры защиты действительно работают.
Как ECDSA связывает подпись с приватным ключом
В блокчейне подпись подтверждает, что действие разрешено владельцем соответствующего приватного ключа. Кошелёк использует этот ключ, чтобы создать подпись, а сеть проверяет её с помощью открытых данных. Сам секретный ключ при этом не отправляется в блокчейн.
В сетях Ethereum и Bitcoin применяется кривая secp256k1. Упрощённо можно представить её как математическую основу, которая позволяет проверить связь подписи с открытым ключом, не раскрывая приватный. Это похоже на проверку печати на документе: проверяющему нужно убедиться, что она подходит, но ему не требуется знать, как именно её изготовили.
ECDSA формирует подпись с участием специального одноразового числа k. Оно должно быть секретным и уникальным для каждой подписи. Это число не совпадает с nonce аккаунта Ethereum, который обозначает порядковый номер транзакции. Название общее, назначение разное: порядковый номер помогает сети отслеживать транзакции аккаунта, а k участвует непосредственно в вычислении криптографической подписи.
Здесь и находится один из наиболее чувствительных участков. Если значение k раскрывается или повторяется при подписании разных сообщений, из подписей можно математически восстановить приватный ключ. Для этого не нужен перебор всех возможных ключей: повтор одного и того же k создаёт достаточно информации для решения алгебраических уравнений.
Это не означает, что любой пользователь, который подписывает много транзакций, автоматически подвергает ключ опасности. Риск связан с дефектом генерации или использования k. Например, причиной может стать слабый генератор случайных чисел или ошибка в библиотеке, создающей подписи.
Приватный ключ редко «ломают» напрямую. Часто проблема начинается с ошибки в операции, которая должна была оставаться одноразовой и секретной.
Повторное использование k: когда ошибка становится критической
Если один и тот же k использован для двух разных сообщений, подписи оказываются связаны математически. Злоумышленнику, который располагает этими подписями и соответствующими данными, может хватить простой алгебры, чтобы вычислить закрытый ключ. После этого защита перестаёт зависеть от того, насколько надёжно пользователь хранил seed-фразу: ключ уже можно вывести из утёкших подписей.
Исторический пример такой ошибки связан с игровой консолью Sony PlayStation 3: в 2010 году повторное использование nonce привело к компрометации ключей. Позже проблемы с генератором псевдослучайных чисел в Java и Android также затронули криптографические ключи. Эти случаи показывают общий принцип: математически надёжная схема не спасает, если программная реализация выдаёт предсказуемые или повторяющиеся значения.
Одно из решений для ECDSA описывает стандарт RFC 6979. Он позволяет вычислять k детерминированно: значение формируется на основе приватного ключа и хеша подписываемого сообщения. Поскольку генерация не зависит от отдельного источника случайных чисел, снижается риск, что неисправный генератор случайных чисел повторит значение или выдаст предсказуемый результат.
Детерминированный способ не означает, что одно значение k применяется постоянно. Для разных сообщений алгоритм вычисляет разные значения, сохраняя предсказуемость процедуры для самой реализации и исключая зависимость от случайного генератора. Пользователю обычно не нужно вручную включать этот механизм: его поддержка зависит от кошелька, криптографической библиотеки и конкретной системы подписи.
При оценке риска полезно держать в уме несколько разных уровней:
- Генерация подписи. Корректно ли приложение создаёт одноразовое значение и пользуется проверенной криптографической библиотекой.
- Проверка подписи. Правильно ли контракт обрабатывает некорректные значения и сверяет адрес подписанта.
- Смысл запроса. Понимает ли пользователь, какое действие разрешает подпись, сколько средств может быть затронуто и к какому приложению относится запрос.
Последний пункт особенно важен для новичка. Кошелёк может показать технически корректную подпись, но пользователь всё равно может одобрить вредоносное действие, если интерфейс не объясняет его достаточно понятно или если человек торопится.
Пластичность подписи и ошибки в смарт-контрактах
У ECDSA есть математическое свойство, которое называют пластичностью подписи. Для определённых параметров подписи значение s можно заменить на n − s, где n связано с порядком группы кривой. Получившаяся пара значений остаётся математически валидной для того же открытого ключа и сообщения.
Практическое следствие касается идентификатора транзакции: если он вычисляется из байтов подписи, изменённый вариант подписи может дать другой идентификатор при том же подтверждаемом действии. Поэтому приложениям нельзя строить логику безопасности на предположении, что одна операция всегда имеет только один возможный идентификатор. В некоторых случаях подобная подмена может нарушить учёт или логику смарт-контракта.
Это свойство не равнозначно получению доступа к приватному ключу. Пластичность сама по себе не позволяет подписать любое новое сообщение от имени владельца. Риск возникает, когда система использует идентификатор транзакции или подпись неосторожно, например при проверке того, выполнялось ли действие раньше.
Есть и более прямой контрактный риск, связанный с функцией Ethereum ecrecover. Она восстанавливает адрес, соответствующий подписи и сообщению. Если параметры некорректны, функция возвращает нулевой адрес address(0). Контракт, который не проверяет этот результат, может ошибочно принять невалидную подпись или неверно обработать авторизацию.
Надёжная проверка должна учитывать не только сам вызов ecrecover, но и то, что возвращаемый адрес не равен нулевому, а также соответствует ожидаемому подписанту. Если контракт использует подпись как разрешение на перевод или изменение состояния, важны и дополнительные ограничения: для какого действия она выдана, где именно её можно применить и как предотвращается повторное использование.
При этом пользователю кошелька обычно не нужно самостоятельно анализировать Solidity-код каждого контракта. Но полезно понимать, почему аудит и качество реализации важны: одна и та же криптографическая подпись может быть обработана безопасно в одном приложении и рискованно в другом.
EIP-712 и подписи, которые выглядят понятнее
Подпись не всегда означает отправку обычной транзакции в сеть. Приложение может попросить подписать данные офчейн, то есть вне блокчейна. Такая подпись может позднее использоваться для авторизации действия, а пользователь в момент подтверждения не платит сетевую комиссию за отдельную транзакцию.
Стандарт EIP-712 предназначен для структурированных данных. Вместо одной длинной строки приложение может представить кошельку поля с типом и содержимым. Например, в запросе могут быть указаны адрес контракта, сеть и параметры действия. Это помогает кошельку показать человеку больше информации о том, что именно он подписывает.
Важную роль играет domainSeparator, который включает параметры домена. Среди них могут быть chainId, то есть идентификатор сети, и verifyingContract, адрес контракта, для которого предназначено сообщение. Такая привязка помогает ограничить применение подписи конкретной сетью и контрактом, снижая риск повторного воспроизведения между разными приложениями или блокчейнами.
Для формирования структурированного хеша используется, в частности, префикс 0x1901. Само наличие стандарта, однако, не делает любой экран подтверждения безопасным. EIP-712 даёт возможность яснее показывать данные и привязывать подпись к контексту, но не исключает обман. Пользователь может попасть на вредоносный сайт, который оформит опасное действие понятными словами или представит запрос так, чтобы важные детали затерялись.
Поэтому перед подтверждением стоит посмотреть, что кошелёк действительно показывает:
- Сеть и приложение. Совпадают ли они с теми, где вы собирались выполнить действие.
- Адрес контракта. Узнаваем ли он, относится ли к ожидаемому сервису.
- Содержание действия. Это подтверждение входа, обмена, выдачи разрешения или операция с активами.
- Срок и ограничения. Есть ли предел по времени, сумме и объёму разрешённых действий.
- Повторное использование. Объясняет ли интерфейс, можно ли применить подпись снова и как её отозвать.
Если кошелёк показывает нечитаемый набор данных или просит подписать сообщение, смысл которого невозможно установить, разумно остановиться и выяснить причину. Не нужно подтверждать запрос лишь потому, что на сайте появилась привычная кнопка или операция обещает быть бесплатной.
ERC-20 Permit: удобство без комиссии и новая зона внимания
Механизм ERC-20 Permit позволяет выдать разрешение на использование токенов с помощью офчейн-подписи. В стандартной схеме для выдачи allowance пользователь отправляет транзакцию в блокчейн и оплачивает газ. Permit позволяет подписать разрешение вне сети, после чего приложение или другой участник может передать его в контракт.
Для пользователя это может быть удобнее: меньше отдельных действий, а иногда и меньше транзакций. Но у подписи есть практический смысл. Она может разрешать контракту расходовать токены в установленном объёме. Если человек воспринимает её как безобидное подтверждение входа, он рискует не заметить, что фактически выдаёт приложению право на списание.
При реализации Permit критичны срок действия подписи и защита от повторного использования. Если в схеме отсутствует deadline или внутренний nonce, перехваченную подпись могут попытаться использовать повторно. Тогда разрешение может остаться применимым дольше, чем ожидал пользователь, или быть передано контракту в другой момент.
Перед подтверждением Permit стоит разобрать его так же внимательно, как обычное разрешение на токены. Посмотрите на адрес контракта, токен, объём разрешения и срок действия. Неограниченная сумма может быть предусмотрена интерфейсом ради удобства, но она расширяет последствия компрометации приложения или ошибочного одобрения. Если сервис позволяет указать конкретный лимит, ограничение суммы обычно делает разрешение понятнее и сужает возможный ущерб.
Подход с несколькими уровнями защиты встречается и за пределами блокчейна. Например, материал о стратегии борьбы с гипертензией у беременных посвящён профилактике рисков в другой области. Сходство здесь только в общем принципе: надёжность складывается из нескольких мер, а не из одной проверки. В криптокошельке это сочетание корректной криптографии, безопасного контракта и внимательного подтверждения пользователем.
Что реально защищает подписи и активы
Безопасность приватных ключей и подписей складывается из работы кошелька, контрактов и самого пользователя. Нельзя заменить один уровень другим: хорошая криптографическая библиотека не поможет, если человек подпишет не то действие, а осторожность пользователя не исправит дефект в контракте.
Для разработчиков и аудиторов практические меры включают использование проверенных библиотек, корректную генерацию k, проверку результата ecrecover, защиту от повторного применения подписи и привязку данных к сети и контракту. RFC 6979 снижает зависимость от качества генератора случайных чисел при создании ECDSA-подписей. EIP-712 позволяет структурировать подписываемые данные и привязать их к домену. В случае Permit значение имеют срок действия, nonce и ограничение разрешённого объёма.
Пользователь может сосредоточиться на том, что доступно непосредственно перед подтверждением:
1. Открывайте кошелёк через привычный путь, а не по случайной ссылке из сообщения. Поддельный сайт может выглядеть убедительно и попросить вполне настоящий запрос на подпись.
2. Читайте описание действия в окне кошелька. Подпись сообщения, перевод токенов и разрешение на их расходование имеют разные последствия.
3. Сверяйте сеть и адрес контракта. Несовпадение с ожидаемым приложением служит поводом остановиться.
4. Относитесь к бессрочным и неограниченным разрешениям внимательно. Если для задачи достаточно меньшего лимита, не обязательно выдавать больше.
5. Не подписывайте непонятные данные в надежде, что это просто технический шаг. Если назначение запроса неясно, закройте окно и проверьте его через официальный интерфейс сервиса.
Подпись не раскрывает приватный ключ сама по себе, однако она может быть разрешением на конкретное действие. Именно поэтому полезно смотреть на неё как на документ, который вы подписываете: кто его предъявил, что в нём разрешено и сколько времени он действует.
Криптографические подписи остаются основой безопасности блокчейнов, а риски возникают вокруг повторного использования nonce, некорректной обработки данных контрактом и обманных запросов кошелька. Для обычного пользователя главный практический навык прост: понимать смысл подтверждения до нажатия кнопки и останавливаться, если интерфейс этот смысл скрывает. Если у вас есть вопрос о конкретной подписи или разрешении, разберите её поля по одному и не торопитесь: в Web3 осторожность часто полезнее скорости.