SHA-1: устаревший стандарт и причины отказа

Алгоритм SHA-1 (Secure Hash Algorithm 1) относится к классу криптографических хеш-функций и был разработан в 1995 году Национальным институтом стандартов и технологий США (NIST). Его задача — преобразование входных данных произвольной длины в фиксированную строку длиной 160 бит (20 байт), называемую хешем или дайджестом.

Основные свойства, которыми должен обладать криптографический хеш:

  • Детерминированность — одинаковый вход всегда даёт одинаковый результат
  • Быстрота вычисления
  • Устойчивость к прообразу — невозможно восстановить исходные данные по хешу
  • Устойчивость ко второму прообразу — трудно найти другое сообщение с тем же хешем
  • Устойчивость к коллизиям — крайне сложно найти два разных сообщения с одинаковым хешем

SHA-1 долгое время считался надёжным и широко применялся в:

  • цифровых подписях
  • SSL/TLS сертификатах
  • системах контроля целостности файлов
  • системах управления версиями (например, Git)

Принцип работы SHA-1

Алгоритм обрабатывает данные блоками по 512 бит и использует итеративную структуру:

  1. Дополнение сообщения (padding) Сообщение расширяется до длины, кратной 512 битам, с добавлением единицы, нулей и длины исходного сообщения.

  2. Инициализация буфера Используются пять 32-битных регистров:

    H0, H1, H2, H3, H4
  3. Обработка блоков Каждый блок проходит 80 раундов преобразований с использованием побитовых операций:

    • AND
    • OR
    • XOR
    • циклические сдвиги
  4. Формирование итогового хеша После обработки всех блоков значения регистров объединяются в 160-битный результат.


Реализация SHA-1 в CryptoJS

Библиотека CryptoJS предоставляет простый интерфейс для вычисления SHA-1:

const hash = CryptoJS.SHA1("Hello, world!");
console.log(hash.toString());

Работа с кодировками:

const hashHex = CryptoJS.SHA1("Hello").toString(CryptoJS.enc.Hex);
const hashBase64 = CryptoJS.SHA1("Hello").toString(CryptoJS.enc.Base64);

Хеширование бинарных данных:

const wordArray = CryptoJS.lib.WordArray.create([0x12345678]);
const hash = CryptoJS.SHA1(wordArray);

Уязвимости SHA-1

Со временем выяснилось, что SHA-1 не удовлетворяет современным требованиям безопасности.

Коллизии

Коллизия — это ситуация, когда:

hash(A) = hash(B), при A ≠ B

Для SHA-1 теоретическая сложность нахождения коллизии составляет (2^{80}), однако практические атаки значительно снизили этот порог.

Ключевые этапы компрометации:

  • 2005 год — первые теоретические атаки (Сяоюнь Ван и коллеги)
  • 2017 год — практическая коллизия (атака SHAttered от Google и CWI)

В рамках SHAttered были созданы два разных PDF-файла с одинаковым SHA-1 хешем.


Причины отказа от SHA-1

1. Нарушение устойчивости к коллизиям

Современные вычислительные мощности позволяют находить коллизии за приемлемое время и стоимость.

2. Угроза цифровым подписям

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

  • один — безопасный
  • другой — вредоносный

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

3. Устаревшая длина хеша

160 бит недостаточно для современных требований. Для сравнения:

  • SHA-256 — 256 бит
  • SHA-512 — 512 бит

4. Давление со стороны стандартов

Организации и протоколы начали запрещать SHA-1:

  • браузеры отказались от SSL-сертификатов с SHA-1
  • NIST объявил SHA-1 устаревшим
  • Git постепенно внедряет переход на SHA-256

Пример атаки коллизии (концептуально)

Идея атаки:

  1. Создаются два разных сообщения:

    M1 ≠ M2
  2. Подбираются так, чтобы:

    SHA1(M1) = SHA1(M2)
  3. Одно сообщение проходит проверку, другое используется злоумышленником.

На практике это достигается сложными математическими методами и требует значительных вычислительных ресурсов, но уже не является недостижимым.


Ограничения SHA-1 в современных системах

Использование SHA-1 считается небезопасным в следующих случаях:

  • хранение паролей
  • цифровые подписи
  • сертификаты
  • проверка целостности критических данных

Допустимое применение:

  • некритичные проверки целостности
  • устаревшие системы, где невозможна миграция

Альтернативы SHA-1

SHA-2

Наиболее распространённая замена:

const hash = CryptoJS.SHA256("Hello");

Преимущества:

  • высокая устойчивость
  • отсутствие известных практических атак

SHA-3

Новый стандарт, основанный на другой конструкции (Keccak):

const hash = CryptoJS.SHA3("Hello", { outputLength: 256 });

BLAKE2 / BLAKE3

Современные быстрые хеш-функции, не входящие в CryptoJS, но активно используемые в индустрии.


SHA-1 в CryptoJS: практические ограничения

CryptoJS продолжает поддерживать SHA-1 по следующим причинам:

  • совместимость со старыми системами
  • образовательные цели
  • историческое наследие

Однако при разработке новых приложений:

  • SHA-1 не должен использоваться
  • рекомендуется переход на SHA-256 или выше

Сравнение SHA-1 и SHA-256

Характеристика SHA-1 SHA-256
Длина хеша 160 бит 256 бит
Устойчивость Нарушена Высокая
Коллизии Найдены Неизвестны
Скорость Быстрее Немного медленнее
Рекомендуется Нет Да

Пример миграции с SHA-1 на SHA-256

Было:

const hash = CryptoJS.SHA1(password);

Стало:

const hash = CryptoJS.SHA256(password);

Для усиления безопасности паролей:

const hash = CryptoJS.PBKDF2(password, salt, {
  keySize: 256/32,
  iterations: 1000
});

Криптографические выводы

  • SHA-1 утратил ключевое свойство — устойчивость к коллизиям
  • безопасность системы зависит не только от алгоритма, но и от его актуальности
  • переход на современные алгоритмы — обязательное требование

Игнорирование этих факторов приводит к уязвимостям даже при корректной реализации кода