MAATRIX / Блог / Контрольная сумма сошлась, а файл битый: когда MD5 вас обманет

Контрольная сумма сошлась, а файл битый: когда MD5 вас обманет

MAATRIX

Файл скачался, md5sum показал ровно то число, что было в письме от коллеги или в файле .md5 рядом с дистрибутивом — и вы со спокойной душой запускаете его в продакшн. А через неделю база не открывается, бэкап не разворачивается или бинарник падает по SIGSEGV на ровном месте. Совпавшая контрольная сумма — это не гарантия целостности файла, а гарантия чего-то куда более узкого. Разберёмся, что именно она доказывает и почему в это узкое место легко провалиться.

Что на самом деле проверяет контрольная сумма

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

Это верно только при одном условии: эталонная сумма была посчитана с заведомо исправного файла — до того, как в него закралось повреждение. Проверка контрольной суммы отвечает на вопрос "изменился ли файл с момента расчёта суммы", а не на вопрос "был ли файл корректен в момент расчёта суммы". Это два разных утверждения, и разница между ними — ровно то место, где ловится описанный ниже сценарий.

Если повреждение произошло до того, как кто-то посчитал MD5 — например, диск уже сбоил, сеть уже роняла пакеты, или процесс записи уже был прерван — то контрольная сумма честно фиксирует уже испорченные байты. Дальше эта сумма путешествует вместе с файлом как "доказательство целостности", и каждая последующая проверка совпадает, потому что файл действительно не менялся *с этого момента*. Испорченным он был раньше.

Классический сценарий: сумма считается слишком поздно

Разберём типичный путь файла от источника до получателя и отметим, где на этом пути обычно вычисляется контрольная сумма:

  1. Файл создаётся или генерируется (экспорт базы, сборка дистрибутива, дамп виртуальной машины).
  2. Файл сохраняется на диск — здесь возможен сбойный сектор, оборванная запись при отключении питания, ошибка контроллера.
  3. Кто-то (часто не тот, кто создавал файл) считает md5sum file.bin и публикует результат.
  4. Файл копируется, архивируется, заливается на файлообменник или в облако.
  5. Получатель скачивает файл и файл с суммой отдельно, сверяет — сумма совпадает.

Проблема в том, что шаг 3 идёт *после* шага 2. Если повреждение случилось на шаге 2, оно уже "зашито" в сумму на шаге 3 — и вся цепочка проверок дальше будет успешной, потому что каждая сверяет файл сам с собой на момент чуть позже повреждения. Чем позже после создания файла посчитана контрольная сумма, тем шире окно, в которое может проскочить порча — сбойный RAID-контроллер, битый USB-накопитель, обрыв при копировании по нестабильному каналу, ошибка в самом процессе экспорта. Похожий сценарий разобран в статье про тихую порчу файлов: данные могут повреждаться на диске незаметно для приложения, без единой ошибки чтения, и любая сумма, посчитанная после такого повреждения, будет защищать уже испорченное состояние.

Отдельно стоит частый бытовой вариант: файл побился уже *после* того, как правильная сумма была где-то записана, но человек, проверяющий целостность, по ошибке пересчитывает сумму заново с битого файла и сравнивает не с оригинальной записанной суммой, а сам с собой — конечно, совпадает. Это не проблема MD5 как алгоритма, а проблема процесса: сверка потеряла смысл, потому что обе стороны сравнения происходят из одного и того же испорченного источника. Есть и параллельная история с записью: если два процесса одновременно пишут в один и тот же файл, итоговое содержимое может оказаться повреждённым без единой ошибки со стороны обеих сторон — разбор такого случая на NFS есть в статье о двух серверах, писавших в один раздел.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Почему это не парадокс, а определение

Важно понимать: MD5 (и любой другой хеш) в этой ситуации работает абсолютно правильно. Криптографическая хеш-функция гарантирует одно свойство — что два разных набора байт с очень высокой вероятностью дадут разные значения хеша (и что вычисление детерминировано). Она ничего не знает и не может знать о том, каким файл "должен был быть". У неё нет доступа к намерению автора файла — только к байтам, которые ей передали на вход.

Отсюда практический вывод: контрольная сумма — это инструмент обнаружения *изменений относительно точки отсчёта*, а не инструмент подтверждения корректности содержимого. Точка отсчёта — это момент вычисления суммы. Всё, что произошло до неё, сумма унаследует как "нормальное состояние", и будет защищать именно это состояние — каким бы оно ни было.

Отдельная слабость: MD5 как криптографический алгоритм

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

Для целостности данных — то есть защиты от случайной, а не умышленной порчи — эта слабость не главная причина проблем из первого раздела: битый сектор диска не подбирает коллизию, он просто портит байты. Но раз современные алгоритмы вроде SHA-256 или SHA-3 не уступают MD5 в скорости на типичном сервере и при этом не несут этой репутационной и теоретической проблемы, разумно по умолчанию использовать их, а MD5 оставлять только для задач, где криптостойкость не требуется вовсе — например, для быстрой дедупликации данных внутри доверенной системы.

Проверьте: сумму какого момента вы на самом деле держите в руках

Прежде чем доверять сошедшейся сумме, стоит явно ответить на вопрос: кто и когда её посчитал.

  • Сумма посчитана автоматически в момент создания файла (например, в CI сразу после сборки артефакта) — высокое доверие: окно для порчи между созданием и расчётом суммы минимально.
  • Сумма посчитана человеком отдельным шагом через какое-то время после создания файла — среднее доверие: возможна порча в промежутке.
  • Сумма посчитана человеком, скачавшим уже "финальный" файл откуда-то со стороны, без доступа к оригиналу — низкое доверие: вы, по сути, проверяете файл сам с собой.
  • Сумма пришла по тому же каналу, что и сам файл (в том же архиве, на том же диске, в том же письме) — низкое доверие: любое повреждение канала или носителя, скорее всего, затронет и файл, и сумму согласованно, либо сумма изначально считалась с уже испорченного файла.

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

Практика: как считать сумму, чтобы она реально что-то доказывала

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

Практические шаги для типичного пайплайна (экспорт базы, сборка дистрибутива, генерация бэкапа на сервере):

# сразу после создания файла — на том же хосте, тем же процессом
pg_dump mydb | gzip > dump.sql.gz
sha256sum dump.sql.gz > dump.sql.gz.sha256

# сумму сохраняем ОТДЕЛЬНО от файла — другой носитель/канал
scp dump.sql.gz.sha256 backup-meta-host:/checksums/dump-$(date +%F).sha256

Ключевой момент — «отдельно от файла». Если сумма лежит рядом с файлом на том же диске, любое событие, способное повредить диск (сбой контроллера, файловая система ушла в read-only, испорченный RAID), с той же вероятностью заденет и сумму, и файл одновременно — либо не заденет ни то, ни другое, и вы ничего не обнаружите. Смысл контрольной суммы как средства обнаружения порчи в том, чтобы она хранилась в независимом месте: в отдельной системе логирования сборок, в отдельном хранилище метаданных, в системе контроля версий, в бэкап-каталоге на другом сервере.

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

#!/usr/bin/env bash
set -euo pipefail

SRC=/var/lib/app/data
DST=/backup/app-$(date +%F).tar.gz
CHECKSUM_DIR=/backup/checksums

tar czf "$DST" -C "$SRC" .
sha256sum "$DST" > "$CHECKSUM_DIR/$(basename "$DST").sha256"

# проверка сразу же, что архив читается и сумма актуальна
sha256sum -c "$CHECKSUM_DIR/$(basename "$DST").sha256"

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

Если работаете с инструментами бэкапа, которые считают контрольные суммы блоков данных сами и в момент записи (restic, BorgBackup, Kopia), они закрывают эту проблему архитектурно: сумма всегда считается с тех байт, которые реально попадают в хранилище, и хранится отдельно от данных в индексе репозитория, поэтому такое несоответствие обнаруживается автоматически при следующей проверке. Ручной пересчёт суммы задним числом с уже сохранённого файла эту гарантию не даёт — вы просто снова получите файл сам с собой.

Для файлов, которые не пересобираются заново, а просто лежат на сервере (конфиги, дистрибутивы, статические артефакты), похожую задачу решает периодический контроль целостности — регулярный пересчёт сумм и сравнение с ранее сохранённым и отдельно хранимым эталоном. Разбор такого подхода без выделенного FIM-агента — на find и sha256sum — есть в статье про контроль целостности файлов.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Если сумма не сошлась — точно ли файл битый?

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

Если сумма сошлась — можно ли быть полностью уверенным в файле?

Нет, именно это и разобрано в статье: совпадение доказывает лишь неизменность файла с момента расчёта суммы, а не корректность самого файла на тот момент.

Стоит ли вообще использовать MD5 в 2026 году?

Для быстрой внутренней дедупликации или проверки случайной порчи внутри доверенной системы — можно, скорость на современном сервере не критична. Для проверки подлинности файлов из недоверенного источника или защиты от умышленной подмены лучше SHA-256 или новее — из-за известной криптографической слабости MD5.

Как понять, что сумма в скачанном .md5-файле вообще заслуживает доверия?

Проверить, откуда и когда она взята: если её опубликовал тот же источник, что раздаёт сам файл, по тому же каналу — это слабая проверка на согласованность канала доставки, а не на исходную корректность файла. Более сильная гарантия — независимо опубликованная сумма (например, в другом репозитории или подписанная GPG-ключом автора).

Что делать, если единственная доступная сумма уже могла быть посчитана с испорченного файла?

Искать альтернативный источник эталона — оригинальный носитель, резервную копию, независимую публикацию суммы — либо проверять целостность файла другими средствами: попыткой открыть/распаковать/выполнить, сверкой размера и структуры, восстановлением из независимого бэкапа для сравнения.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →