История атак на пароли: радужные таблицы, брутфорс, словарные атаки

Появление паролей как основного механизма аутентификации практически сразу привело к развитию методов их взлома. На протяжении десятилетий атакующие совершенствовали способы получения паролей: от простого перебора до сложных криптоаналитических техник. Именно история атак сформировала современные требования к библиотекам хеширования паролей, включая использование соли, адаптивных алгоритмов и устойчивости к GPU-ускоренному перебору.


Первые системы хранения паролей

Ранние операционные системы часто хранили пароли в открытом виде. Это означало, что любой пользователь с доступом к файлу базы данных мог моментально увидеть учетные данные всех остальных пользователей.

Позже появились криптографические хеш-функции. Вместо хранения самого пароля система сохраняла результат вычисления:

hash = H(password)

Во время входа пользователь вводил пароль, система снова вычисляла хеш и сравнивала его с сохранённым значением.

Такой подход устранял необходимость хранить пароль напрямую, однако быстро выяснилось, что обычное хеширование не обеспечивает достаточной защиты.


Брутфорс-атаки

Принцип работы

Брутфорс (brute force) — полный перебор возможных комбинаций символов до нахождения совпадения.

Простейший сценарий:

  1. злоумышленник получает хеш пароля;
  2. начинает генерировать варианты паролей;
  3. вычисляет их хеши;
  4. сравнивает результаты.

Если:

hash(candidate) === stolenHash

то пароль найден.


Пример простого перебора

const crypto = require('crypto')

const targetHash =
  '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8'

const chars = 'abcdefghijklmnopqrstuvwxyz1234567890'

function sha256(value) {
  return crypto
    .createHash('sha256')
    .update(value)
    .digest('hex')
}

function bruteForce(length, current = '') {
  if (current.length === length) {
    if (sha256(current) === targetHash) {
      console.log('Найден пароль:', current)
      process.exit()
    }
    return
  }

  for (const char of chars) {
    bruteForce(length, current + char)
  }
}

bruteForce(4)

Рост вычислительных мощностей

Скорость брутфорса напрямую зависит от производительности оборудования.

Исторические этапы

Период Скорость перебора
1970-е сотни хешей/сек
1990-е тысячи хешей/сек
2000-е миллионы хешей/сек
Современные GPU миллиарды хешей/сек

Почему быстрые хеш-функции опасны

Алгоритмы вроде:

  • MD5
  • SHA1
  • SHA256

создавались для скорости, а не для защиты паролей.

Для файловой целостности высокая скорость полезна:

быстрее вычисление → лучше производительность

Для паролей это катастрофа:

быстрее вычисление → быстрее перебор

Современная видеокарта может вычислять миллиарды MD5-хешей в секунду.


Словарные атаки

Идея словарной атаки

Большинство пользователей не создают случайные пароли. Вместо этого используются:

  • обычные слова;
  • имена;
  • даты;
  • популярные комбинации;
  • шаблоны клавиатуры.

Примеры:

password
qwerty
admin123
welcome
123456

Словарная атака использует заранее подготовленный список популярных паролей.


Пример словарной атаки

const crypto = require('crypto')
const fs = require('fs')

const dictionary = fs
  .readFileSync('passwords.txt', 'utf8')
  .split('\n')

const targetHash =
  '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8'

function sha256(value) {
  return crypto
    .createHash('sha256')
    .update(value)
    .digest('hex')
}

for (const password of dictionary) {
  if (sha256(password.trim()) === targetHash) {
    console.log('Пароль найден:', password)
    break
  }
}

Эффективность словарных атак

Словарная атака намного эффективнее полного перебора.

Причины

Использование человеческой предсказуемости

Люди склонны:

  • повторять популярные шаблоны;
  • использовать короткие слова;
  • добавлять цифры в конец;
  • заменять буквы символами:
password → p@ssw0rd

Огромные базы утечек

После крупных утечек появились коллекции реальных паролей:

  • RockYou;
  • Collection #1;
  • LinkedIn leaks;
  • Adobe leaks.

Эти базы стали основой современных словарей.


Гибридные атаки

Позже словарные атаки объединились с мутациями:

admin
admin1
admin123
Admin123!

Такие техники называются rule-based attacks.

Популярные инструменты:

  • Hashcat;
  • John the Ripper.

Радужные таблицы

Проблема повторяемости хешей

Если два пользователя имеют одинаковый пароль:

password123

то при обычном хешировании получится одинаковый результат:

sha256("password123")

ef92b778...

Это позволяет заранее вычислить огромные базы соответствий:

пароль → хеш

Что такое радужная таблица

Радужная таблица (rainbow table) — заранее подготовленная база:

хеш → исходный пароль

Вместо вычисления хеша во время атаки злоумышленник просто ищет совпадение в таблице.


Почему радужные таблицы были революцией

До их появления атакующий должен был:

  1. вычислять каждый хеш;
  2. сравнивать результаты;
  3. повторять процесс для каждой цели.

Радужные таблицы позволили:

вычислить всё заранее

После этого взлом становился почти мгновенным.


Пример концепции

Обычный перебор

password1 → hash1
password2 → hash2
password3 → hash3

Во время атаки:

украденный hash2 → поиск → password2

Ограничение по размеру

Полная таблица для всех возможных комбинаций слишком велика.

Например:

8 символов ASCII

дают десятки триллионов вариантов.

Для уменьшения размера использовались:

  • цепочки преобразований;
  • reduction functions;
  • компрессия вычислений.

Rainbow Chains

Радужные таблицы строились как цепочки:

пароль → хеш → преобразование → новый пароль → новый хеш

Хранились только начало и конец цепочки.

Это резко уменьшало размер таблицы.


Появление соли (Salt)

Главная защита против радужных таблиц

Решением стала соль — случайная строка, добавляемая к паролю перед хешированием.

hash = H(password + salt)

Пример

const crypto = require('crypto')

const password = 'secret123'
const salt = crypto.randomBytes(16).toString('hex')

const hash = crypto
  .createHash('sha256')
  .update(password + salt)
  .digest('hex')

console.log({ salt, hash })

Почему соль работает

Даже если два пользователя имеют одинаковый пароль:

secret123

разные соли создадут разные хеши:

hash(secret123 + salt1)
hash(secret123 + salt2)

Последствия для атакующего

Соль уничтожает эффективность радужных таблиц.

Теперь злоумышленнику необходимо:

генерировать таблицу отдельно для каждой соли

Это делает предвычисления практически бесполезными.


GPU и FPGA-ускорение

Рост параллельных вычислений

Современные атаки выполняются не на CPU, а на:

  • GPU;
  • FPGA;
  • ASIC.

GPU способны одновременно вычислять тысячи потоков хеширования.


Почему это опасно

Алгоритмы вроде SHA256 чрезвычайно хорошо распараллеливаются.

Пример:

1 GPU → миллиарды SHA256/сек

Даже длинные пароли становятся уязвимыми при слабом алгоритме хеширования.


Переход к медленным алгоритмам

Основная идея

Чтобы усложнить перебор, появились специальные password hashing algorithms:

  • bcrypt;
  • scrypt;
  • Argon2;
  • PBKDF2.

Они специально делают вычисление дорогим.


bcrypt

bcrypt основан на Blowfish и включает:

  • соль;
  • адаптивную стоимость;
  • многократные раунды.

Пример:

const bcrypt = require('bcrypt')

async function run() {
  const hash = await bcrypt.hash('secret123', 12)

  console.log(hash)

  const valid = await bcrypt.compare(
    'secret123',
    hash
  )

  console.log(valid)
}

run()

Стоимость вычислений

Параметр cost:

bcrypt.hash(password, 12)

означает:

2^12 раундов

Увеличение cost:

  • замедляет сервер;
  • но многократно замедляет атакующего.

Memory-hard алгоритмы

Проблема GPU

GPU отлично справляются с вычислениями, но имеют ограничения памяти.

Это привело к появлению memory-hard алгоритмов.


scrypt

scrypt требует значительный объём памяти при вычислении.

Это делает массовый параллельный перебор значительно дороже.


Argon2

Argon2 — победитель Password Hashing Competition.

Варианты:

Версия Назначение
Argon2d защита от GPU
Argon2i защита от side-channel
Argon2id комбинированный вариант

Пример Argon2

const argon2 = require('argon2')

async function run() {
  const hash = await argon2.hash('secret123')

  console.log(hash)

  const valid = await argon2.verify(
    hash,
    'secret123'
  )

  console.log(valid)
}

run()

История крупнейших утечек

RockYou (2009)

Утекло более 32 миллионов паролей.

Главная проблема:

пароли хранились в открытом виде

Эта утечка стала основой огромного количества словарей.


LinkedIn (2012)

Использовался SHA1 без соли.

Последствия:

  • массовый взлом;
  • быстрый перебор;
  • появление миллионов раскрытых паролей.

Adobe

Adobe использовала слабое шифрование и плохие практики хранения.

Исследователи смогли:

  • анализировать шаблоны;
  • восстанавливать пароли;
  • выявлять популярные комбинации.

Современные методы атак

Credential Stuffing

После утечек злоумышленники начали массово проверять:

email + пароль

на других сервисах.

Причина успеха:

повторное использование паролей

Password Spraying

Вместо перебора множества паролей для одного аккаунта используется:

один популярный пароль для множества аккаунтов

Например:

Summer2025!

Это помогает обходить блокировки.


Offline cracking

Самый опасный сценарий.

Атакующий получает:

  • базу хешей;
  • соли;
  • параметры алгоритма.

После этого перебор выполняется локально без ограничений сервера.


Почему password-hash библиотеки критически важны

Современные библиотеки решают сразу несколько задач:

Угроза Механизм защиты
Радужные таблицы Соль
GPU-брутфорс Медленные алгоритмы
Массовый перебор Cost factor
ASIC/GPU Memory-hard вычисления
Коллизии Современные алгоритмы

Ошибки разработчиков

Использование SHA256 напрямую

Опасный вариант:

const hash = crypto
  .createHash('sha256')
  .update(password)
  .digest('hex')

Причины:

  • слишком быстро;
  • отсутствие встроенной соли;
  • уязвимость к GPU.

Самодельные схемы

Некоторые разработчики пытаются усложнить алгоритм:

sha256(md5(password + secret))

Это не делает систему безопасной.

Криптография требует:

  • проверенных алгоритмов;
  • открытого анализа;
  • стандартизированных решений.

Недостаточная стоимость bcrypt

Слишком маленький cost:

bcrypt.hash(password, 4)

делает перебор дешёвым.

Современные рекомендации обычно находятся в диапазоне:

10–14+

в зависимости от мощности серверов.


Влияние истории атак на современные стандарты

История атак полностью изменила подход к хранению паролей.

Современные требования включают:

  • уникальную соль;
  • memory-hard алгоритмы;
  • адаптивную сложность;
  • защиту от параллельного перебора;
  • устойчивость к утечкам базы данных.

Именно из-за развития:

  • брутфорса;
  • словарных атак;
  • радужных таблиц;
  • GPU-ускоренного перебора;

появились специализированные библиотеки password hashing, без которых безопасная аутентификация стала невозможной.