TGViewer
Пингискок Пингискок @rmrf_0 · 618 subscribers
Post #15 575
CERTIK это конечно очень важно и нужно. А что с вебом делать то будем?

Как ДОЛЖНА работать Web3 аутентификация

Нормальный flow аутентификации через кошелёк:

1. Клиент серверу: "Хочу войти, мой адрес 0xАБВ"
2. Сервер клиенту: "Подпиши этот уникальный nonce: a7f3b2..."
3. Клиент подписывает nonce приватным ключом в MetaMask
4. Клиент серверу: "Вот подпись: 0x8e3f..."
5. Сервер проверяет подпись через ecrecover - совпадает ли она с адресом 0xАБВ
6. Только после проверки - выдаёт JWT

Смысл в том, что приватный ключ есть только у владельца кошелька. Без подписи доказать владение адресом невозможно.

Как это работает у исследуемого проекта

1. Клиент серверу: "Мой адрес 0xАБВ"
2. Сервер: "Ок, держи JWT" - всё, конец

Шаги 2-5 просто отсутствуют. Сервер верит на слово.

Более того, endpoint /api/auth/verify который по названию должен проверять подпись - принимает параметры signature и nonce, но полностью их игнорирует:

# Фейковая подпись "FAKE" - принимается
curl -sk -X POST 'https://example.com/api/auth/verify' \
-H 'Content-Type: application/json' \
-d '{"wallet_address":"0x.....","signature":"FAKE","nonce":"FAKE"}'

# Ответ: 200 OK + валидный JWT


Почему это критично

Ethereum адрес - публичная информация. Любой адрес можно посмотреть на etherscan.io. Это как логин без пароля. Зная адрес кошелька пользователя, атакующий:

1. Отправляет один POST запрос с этим адресом
2. Получает JWT токен
3. С этим токеном читает /api/user - а там в ответе прилетают password_hash, two_fa_code, reset_token
4. Полный захват аккаунта

Почему это работает (вероятная причина)

Скорее всего, разработчики:
- Написали auth endpoints как заглушки с планом "потом добавим проверку подписи"
- Использовали catch-all route (/api/auth/[...slug]) в Next.js, который на любой POST с wallet_address создаёт/находит пользователя и выдаёт JWT
- Функция ecrecover или verifyMessage либо не вызывается, либо её результат не проверяется перед выдачей токена
- Все 8 auth endpoints проходят через один и тот же handler, который сразу делает jwt.sign({userId: user.id}) без проверки

В клиентском JS видно, что фронтенд всё делает правильно - вызывает MetaMask, получает подпись, отправляет её. Но бэкенд эту подпись не проверяет.

С учетом того что у проекта есть свой токен - становится не сложным поиск адресов всех холдеров/пользователей этого проекта.
  • 🔥 6
  • ❤ 2
  • ⚡ 1
  • 🗿 1
More from @rmrf_0
  1. May 1, 2026Белый хакер: “может, всё-таки responsibly disclose?” Google: давай! memory corruption - 50…
  2. Apr 13, 2026DeFi-протоколы не взламывают. Они просто не закрыты. Омар рассказал кейс про то как их AI-…
  3. Apr 8, 2026Claude Mythos.. .. еще не выпущен, но опубликовали исследование про него: https://red.anth…
  4. Apr 6, 2026Как КНДР полгода играла в квант-фонд и вынесла $285M из Drift Drift - крупнейший перпетуал…
  5. Apr 3, 2026Мое лицо когда закрыл серию статей (думайте, какое именно лицо мое) Закрыл, да не полность…
  6. Mar 28, 2026Продолжение серии про JWT - шесть новых статей Криптография, шифрование, библиотеки, OAuth…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →