Как взломали LinkedIn через предсказуемые токены восстановления паролей и почему это может случиться снова
В 2012 году произошла история, которую многие помнят только через заголовок «утекли пароли LinkedIn». Но менее известная часть — токены восстановления пароля были предсказуемыми, и это позволяло злоумышленникам не только сбрасывать чужие пароли, но и массово брать контроль над аккаунтами.
Это не «хак суперкомпьютером». Это ошибка в том, что казалось мелочью.
Что такое токен восстановления?
Когда пользователь нажимает «Забыли пароль?», система создаёт одноразовый токен, отправляет его по email/хешом в ссылке и затем проверяет его при переходе.
Этот токен - единственная грань между пользователем и атакующим. Он должен быть непредсказуемым, длинным и однозначно связанным с запросом.
У LinkedIn на тот момент это выглядело примерно так (упрощённо):
https://linkedin.com/reset?user=12345&token=ab45cd67
То есть проблема была не в форме, а в содержании.
Что сделали неправильно?
Токены имели структуру, которую можно было угадывать, потому что они:
- генерировались частично на основе timestamp
- использовали предсказуемый PRNG
- имели ограниченную длину (мало энтропии)
- инкрементировались относительно последнего значения
Это не обязательно выглядело как token = time(), но суть равна: если у тебя есть несколько токенов разных пользователей, ты можешь восстановить последовательность и предсказать следующие.
Это классическая уязвимость: предсказуемый seed + короткий токен = чужой аккаунт
Как это эксплуатировалось?
Атакующий мог:
- Запросить сброс паролей нескольких своих аккаунтов.
- Получить токены.
- Вычислить закономерность.
- Сгенерировать токены для других ID.
- Переходить по ссылкам сброса без запроса.
То есть можно было не просить сброс пароля, а просто сформировать ссылку, по которой система скажет: «Да, токен ваш».
Уязвимость в механизме восстановления паролей делала токены частично предсказуемыми, что позволяло атакующему сбрасывать пароли, формируя ссылки без запроса со стороны пользователя. Это сочеталось с утечкой 6.5 млн хешей паролей, созданных с SHA-1 без соли, что привело к массовому угону аккаунтов. Размер ущерба LinkedIn публично не раскрывал, но это привело к переходу на крипто-устойчивые токены и обновлению всей системы аутентификации.
Почему это произошло?
Потому что разработчики допустили три классические ошибки:
1. Использовали PRNG, а не CSPRNG.
2. Сидировали генератор gпредсказуемыми данными.
3. Токен был коротким.
Плюс - токены не были связаны с одноразовой сессионной привязкой, поэтому система принимала их «в вакууме», а не в контексте запроса.
Как нужно делать правильно
- Использовать CSPRNG, например: crypto.getRandomValues() /dev/urandom ChaCha20
- Минимум 128 бит энтропии 16 байт в hex дают 32 символа - это база.
- Привязывать токен к устройству/сессии/пользователю. Токен должен работать только в связке с запросом.
- Одноразовость: срабатывает 1 раз — и сгорает.
- Истекает быстро 10–30 минут, не сутки.
- Логировать попытки валидации, а не только выдачу.
Почему важно писать об этом в 2025 году
Потому что «предсказуемый токен» - это не ошибка эпохи PHP 5. Это ошибка людей, которые: делают регистрацию Web3-кошельков прямо в браузере, генерируют токены в Unity для F2P-игр, пишут CAPTCHA-бэкэнды через Math.random() и после этого удивляются, что аккаунты угнали.
Большинство разработчиков уверены, что безопасность - это про шифрование. Но токен "qwerty123" - это даже не про дешифровать, это просто угадать.
Случайность - это не просто число. Случайность - это гарантия, что ты не станешь чьей-то добычей.