Почему совпадение хеша не гарантирует безопасность файла

Совпадение контрольной суммы (хеша) подтверждает только одно: битовая последовательность файла совпадает с эталоном на момент вычисления. Это полезно для обнаружения случайных ошибок передачи или повреждений диска. Но для безопасности — защиты от подмены, вредоносного кода или несанкционированных изменений — совпадения хеша недостаточно. В статье разбираем, почему это так, какие атаки это позволяют, и какие механизмы реально защищают целостность и подлинность.

Что на самом деле проверяет хеш-функция

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

  • Однонаправленность — по хешу нельзя восстановить исходные данные.
  • Стойкость к поиску преобраза — дан хеш h, найти любое сообщение m такое, что hash(m) = h, вычислительно нереально.
  • Стойкость к коллизиям — найти две различные сообщения m1 ≠ m2 с одинаковым хешем вычислительно нереально.

Если файл скачан, и его SHA-256 совпадает с опубликованным разработчиком — вы знаете, что биты не изменились в пути. Но вы не знаете:

  • Был ли исходный файл вредоносным изначально (компрометация сборки, supply chain).
  • Не найдена ли коллизия, позволяющая подсунуть другой файл с тем же хешем.
  • Не использует ли алгоритм уязвимый к атакам преобраза или расширения длины.
  • Не подменён ли сам эталонный хеш на сайте или в репозитории.

Коллизии: когда два разных файла дают один хеш

Парадокс дней рождения и сложность поиска

Для хеша длины n бит идеальная стойкость к коллизиям составляет 2^(n/2) операций (атака по дням рождения). Для SHA-256 это 2^128 — астрономически много. Но для устаревших алгоритмов реальность иная:

Алгоритм Длина хеша Теоретическая стойкость к коллизиям Статус на 2024 год
MD5 128 бит 2^64 Полностью сломан: коллизии находятся за секунды на обычном CPU
SHA-1 160 бит 2^80 Практическая коллизия демонстрирована (SHAttered, 2017); chosen-prefix коллизии — 2019
SHA-256 256 бит 2^128 Коллизий не найдено, считается стойким
SHA-3 / BLAKE2/3 256+ бит 2^128+ Стойкие, нет известных атак

Chosen-prefix collisions — реальная угроза

Обычная коллизия находит любые два сообщения с одинаковым хешем. Chosen-prefix collision позволяет злоумышленнику взять два заранее заданных префикса (например, заголовки двух разных исполняемых файлов) и дописать к каждому специально подобранные суффиксы так, что итоговые хеши совпадут.

Это означает: можно создать два разных PDF, два разных исполняемых файла или два разных контейнера Docker с идентичным SHA-1, при этом оба файла будут валидными и выполнять разный код. Атака на SHA-1 стоит порядка $45–100 тысяч на облачных GPU (цены 2020–2023 гг.) — доступно для мотивированного атакующего.

Пример сценария

Разработчик публикует релиз с SHA-1 хешем. Злоумышленник заранее готовит два варианта: легитимный и с бэкдором. Подбирает суффиксы для коллизии. Подменяет файл на зеркале или в репозитории. Пользователь проверяет SHA-1 — совпадает. Запускает заражённый бинарь.

Именно поэтому SHA-1 и MD5 запрещены для любых целей безопасности (подписание кода, сертификаты TLS, верификация релизов). Они допустимы только для некритичных проверок целостности при передаче данных, где угроза намеренной подмены исключена.

Атаки преобраза: когда хеш известен, ищется исходник

Первая преобразная (preimage): дан хеш h, найти m такое, что hash(m) = h. Вторая преобразная: дан m1, найти m2 ≠ m1 с тем же хешем.

Для стойких хешей (SHA-256, SHA-3, BLAKE2) лучшие известные атаки требуют ~2^n операций — нереально. Но для слабых алгоритмов или нестандартного использования (например, hash(secret || message) без HMAC) существуют атаки расширения длины.

Атака расширения длины (Length Extension Attack)

Меркле-Дамгård конструкция (MD5, SHA-1, SHA-256, SHA-512) позволяет: зная hash(m) и длину m, вычислить hash(m || padding || m’) для произвольного m’ — не зная m.

Это ломает схемы вида token = hash(secret || data) как MAC. Атакующий может дописать данные и вычислить валидный токен без знания секрета. Защита — использовать HMAC (HMAC-SHA256(key, data)) или хеши на базе स्पонджа (SHA-3, BLAKE2/3), устойчивые к расширению длины.

Supply chain: когда «оригинальный» файл уже вредоносен

Самый частый вектор компрометации в 2020–2024 гг. — не коллизии хешей, а подмена на этапе сборки или распространения:

  • Компрометация CI/CD (SolarWinds, CodeCov, 3CX).
  • Вредоносные зависимости в npm/PyPI/RubyGems (typosquatting, dependency confusion).
  • Подмена артефактов в репозитории (GitHub Actions, Docker Hub).
  • Скомпрометированные ключи подписи разработчика.

В этих случаях хеш совпадает с опубликованным, потому что публикуемый артефакт уже содержит вредоносный код. Проверка хеша ничего не обнаружит.

Что помогает против supply chain атак

  • Воспроизводимые сборки (reproducible builds) — несколько независимых сторон собирают из исходников идентичные бинарники. Если хеш совпадает у всех — вероятность подмены в сборке снижается.
  • Подписание артефактов — криптографическая подпись (Ed25519, RSA-PSS, ECDSA) приватным ключом разработчика. Проверка подписи подтверждает: файл создан владельцем ключа и не изменён.
  • Transparency logs / Sigstore / Rekor — публичный журнал подписей, позволяющий аудировать историю релизов.
  • SBOM (Software Bill of Materials) — список зависимостей с версиями и хешами для аудита.
  • Политика pinning зависимостей — фиксация точных версий и хешей в lock-файлах.

Подмена эталонного хеша: доверяй, но проверяй источник

Если атакующий получил доступ к сайту проекта, репозиторию релизов или DNS — он может заменить и файл, и опубликованный хеш. Пользователь скачает оба, проверит — совпадут. Примеры:

  • Компрометация веб-сервера (Linux Mint 2016, PHP 2021).
  • DNS-спуфинг / BGP-хайджек репозитория.
  • Атака на аккаунт мейнтейнера в GitHub / PyPI / npm.

Защита — многофакторная верификация источника:

  • Сравнение хеша из нескольких независимых источников (сайт, GitHub Releases, зеркала, mailing list).
  • Проверка криптографической подписи (GPG, Minisign, cosign) — ключ разработчика сложнее скомпрометировать, чем веб-страницу.
  • Использование transparency logs (Sigstore, Go checksum database).
  • Проверка TLS-сертификата и Certificate Transparency логов при скачивании по HTTPS.

Что на практике обеспечивает безопасность файла

Иерархия гарантий (от слабого к сильному)

  1. CRC32 / Adler-32 — только случайные ошибки передачи. Никакой безопасности.
  2. MD5 / SHA-1 — случайные ошибки + устойчивость к нецелевым повреждениям. Коллизии тривиальны — не для безопасности.
  3. SHA-256 / SHA-512 / BLAKE2b / BLAKE3 — стойкость к коллизиям и преобразам. Хорошо для проверки целостности при доверенном источнике.
  4. HMAC-SHA256 / KMAC / BLAKE2 с ключом — целостность + подлинность (требует общего секрета).
  5. Цифровая подпись (Ed25519, RSA-PSS, ECDSA-P256) + PKI / Web of Trust / Sigstore — целостность + подлинность + неотрекаемость + публичная верифицируемость. Золотой стандарт для релизов ПО.
  6. Воспроизводимая сборка + подпись + transparency log — максимальный уровень доверия к бинарнику.

Практический чек-лист верификации релиза

  1. Получите файл с официального источника (HTTPS, проверенный домен).
  2. Проверьте TLS-сертификат (домен, срок, CA, CT-логи).
  3. Скачайте файл подписи (.sig, .asc, .minisig) и публичный ключ разработчика из независимого источника (keyserver, страница проекта в GitHub, Keybase, DNS-OPENPGPKEY).
  4. Проверьте подпись: gpg —verify file.sig file или minisign -Vm file -P pubkey.
  5. При необходимости — сверьте SHA-256/BLAKE2b с опубликованным значением как дополнительную проверку.
  6. Для критических компонентов — проверьте воспроизводимую сборку или наличие записи в transparency log (Rekor, Go checksum db).

Типичные ошибки и заблуждения

  • «SHA-256 совпал — значит файл чистый» — нет, значит только битово идентичен тому, что хешировался. Источник мог быть скомпрометирован.
  • «MD5 достаточно для проверки скачанного образа» — нет, атакующий может подготовить коллизию заранее. Используйте SHA-256 или BLAKE2b.
  • «Хеш в имени файла (filename.sha256) — это защита» — нет, это удобство. Файл с хешем можно подменить вместе с образом.
  • «Проверяю хеш, который лежит рядом с файлом на том же сервере» — циклическая проверка. Нужен независимый источник хеша или подпись.
  • «GPG сложен, лучше проверить SHA-256» — GPG/Minisign/cosign сложнее в первый раз, но дают гарантию подлинности, которой нет у голого хеша. Minisign и cosign — простые современные альтернативы.
  • «Подпись есть, но я не проверяю отпечаток ключа» — если не верифицируете fingerprint ключа через сторонний канал, доверяете первому попавшемуся ключу (TOFU — trust on first use).

Сценарии: что делать в конкретных ситуациях

Ситуация Минимум проверок Рекомендуемый уровень
Скачивание образа ОС / прошивки роутера SHA-256 с официального HTTPS-сайта GPG/Minisign подпись + сверка fingerprint ключа через второй канал
Установка пакета из системного репозитория (apt, dnf, pacman) Автоматическая проверка подписи репозитория менеджером пакетов Включена по умолчанию; не отключайте проверку подписей
pip install / npm install / cargo add Hash pinning в lock-файле Включение требования подписей (npm —require-scripts, pip —require-hashes), использование sigstore/cosign для контейнеров
Запуск бинарника из GitHub Releases Сравнение SHA-256 с релизом Проверка cosign/Minisign подписи мейнтейнера + reproducible build (если есть)
Обмен файлами внутри команды SHA-256 в защищённом чате HMAC с общим секретом или подпись Ed25519
Верификация бэкапа / архива SHA-256 / BLAKE3 при создании Подпись архива ключом архивиста + периодическая перепроверка

Инструменты для практической работы

  • sha256sum / sha512sum / b2sum / b3sum — быстрый расчёт хешей (coreutils, b2sum из b2-tools, b3sum из b3sum пакета).
  • Minisign — простое подписание/верификация Ed25519, короткие ключи, нет ключевых серверов, подходит для релизов.
  • cosign / Sigstore — keyless подписание через OIDC, transparency log Rekor, интеграция с контейнерами и бинарниками.
  • GPG / GnuPG — классика, Web of Trust, поддержка везде, но сложнее в использовании.
  • age / rage — современное симметричное/асимметричное шифрование, можно использовать для зашифрованных подписей.
  • reprotest / diffoscope — проверка воспроизводимости сборок.
  • in-toto / SLSA — фреймворки для защиты supply chain от исходников до артефакта.

Ограничения: чего ни хеш, ни подпись не гарантируют

Даже идеальная криптография не защитит от:

  • Уязвимостей в самом коде (баги, логические ошибки, zero-day).
  • Злонамеренного кода, легально добавленного разработчиком (backdoor by design).
  • Компрометации среды выполнения (заражённое ОС, гипервизор, hardware implants).
  • Социальной инженерии (пользователь сам запускает вредонос, игнорируя предупреждения).
  • Атак на цепочку доверия ключей (скомпрометированный CA, подмена ключа в keyserver без проверки fingerprint).

Хеш и подпись — это инструменты верификации происхождения и целостности. Они отвечают на вопрос «этот файл именно тот, что выпустил автор?». На вопрос «безопасен ли этот код?» они ответить не могут — нужен аудит кода, SAST/DAST, песочницы, мониторинг поведения.

Резюме: следующий шаг

Главный принцип: хеш — для целостности, подпись — для подлинности, воспроизводимая сборка + transparency log — для доверия к процессу.

Если вы сегодня проверяете только SHA-256 из того же источника, что и файл — начните с двух действий:

  1. Найдите и импортируйте публичный ключ подписи разработчика (GPG/Minisign/cosign) из независимого источника.
  2. Настройте автоматическую проверку подписей для ваших основных каналов получения ПО (пакетный менеджер, CI/CD, container runtime).

Для критических систем добавьте требование воспроизводимых сборок и проверку записей в transparency logs. И помните: совпадение хеша — это начало проверки, а не её конец.

Материал носит информационный характер и не заменяет профессиональную оценку безопасности в конкретной инфраструктуре. При защите критических систем обратитесь к специалисту по информационной безопасности для аудита цепочки поставок и модели угроз.

PEFile.ru