Если вы когда-то полагались на ETag как на «MD5 от файла» в S3/Object Storage, сегодня это уже опасное упрощение. Современные S3-совместимые хранилища используют multipart upload, шифрование на стороне сервера, а также явные контрольные суммы (checksum-algorithm). Все это делает классический подход проверок по ETag ненадежным. Разбираем, что на самом деле стоит за ETag, как работают контрольные суммы CRC32/CRC32C/SHA1/SHA256, и как правильно верифицировать загрузки — особенно крупные (многогигабайтные) и разрезанные на части.
ETag в HTTP vs ETag в S3
В HTTP заголовок ETag — это валидатор ресурса для кэширования и условных запросов (If-None-Match, If-Match). Он не обязан быть хэшем содержимого, хотя часто им является. В S3-совместимых сервисах значение ETag возвращается в ответах на операции загрузки и в HEAD/GET объекта, но семантика ETag специфична для реализации хранилища.
Исторически в S3 для одиночной загрузки (single-part PUT) без шифрования ETag совпадал с MD5 тела. Из-за этого многие инструменты (бэкаперы, синхронизаторы, CDN-интеграции) начали трактовать ETag как «MD5 от файла». Это работает не всегда и приводит к ложным срабатываниям или пропущенным расхождениям.
Когда ETag совпадает с MD5, а когда — нет
Совпадение с MD5 чаще всего наблюдается при:
- Одиночном PUT небольшого файла (не multipart),
- Без шифрования на стороне сервера,
- Без трансформаций на стороне хранилища.
ETag перестает быть MD5 в случаях:
- Multipart upload: ETag имеет вид
"<hex>-<parts>", где<hex>— MD5 от конкатенации MD5 каждой части, а<parts>— количество частей. Это не MD5 всего файла. - Шифрование на стороне сервера (SSE): ETag может перестать быть хэшем содержимого (и это зависит от провайдера/режима SSE). Полагаться на ETag как на MD5 нельзя.
- Некоторые S3-совместимые реализации меняют стратегию вычисления ETag или включают служебные детали реализации.
Практическое правило: никогда не используйте ETag как единственный источник истины для контроля целостности содержимого. Используйте явные контрольные суммы.
Content-MD5: полезно, но ограниченно
Заголовок Content-MD5 (в Base64) может использоваться при PUT Object для верификации целостности на стороне сервера. Но у него есть ограничения:
- Работает только для одиночной загрузки,
- MD5 сегодня — компромиссный алгоритм: быстрый, но криптографически слабый,
- В multipart upload
Content-MD5не решает задачу контроля целостности всего объекта.

ChecksumAlgorithm в S3: CRC32/CRC32C/SHA1/SHA256
Современный способ — использовать «явные» контрольные суммы. В API это опции ChecksumAlgorithm и связанные заголовки x-amz-checksum-*. Идея простая:
- Клиент сообщает, какой алгоритм применяется (CRC32, CRC32C, SHA1, SHA256),
- Передает вычисленную сумму (Base64) в запросе,
- Хранилище проверяет соответствие и сохраняет результат,
- Сервер возвращает поля
ChecksumCRC32,ChecksumCRC32C,ChecksumSHA1,ChecksumSHA256в ответах наPUT,HEAD,GET.
Преимущества:
- Однозначная и переносимая верификация, независимая от ETag,
- Работает с multipart (включая контроль частей и итогового объекта),
- Можно выбирать баланс между скоростью и надежностью (CRC32/CRC32C быстрее, SHA256 надежнее).
Единичная загрузка с checksum-algorithm (CLI)
В простом случае объект можно загрузить одной операцией и сразу включить контрольную сумму. Пример с SHA256 в AWS CLI v2 (Base64 от бинарного дайджеста):
openssl dgst -binary -sha256 file.bin | base64
aws s3api put-object --bucket my-bucket --key path/file.bin --body file.bin --checksum-algorithm SHA256
aws s3api head-object --bucket my-bucket --key path/file.bin --checksum-mode ENABLED --query '{ETag:ETag,ChecksumSHA256:ChecksumSHA256,Size:ContentLength}'
CLI сам рассчитает и передаст нужные заголовки, а ответ HEAD покажет сохраненную контрольную сумму. Если вы хотите дополнительно потребовать проверку MD5 на сервере, можно одновременно передать --content-md5 (Base64 от MD5):
openssl dgst -binary -md5 file.bin | base64
aws s3api put-object --bucket my-bucket --key path/file.bin --body file.bin --content-md5 <base64-md5> --checksum-algorithm SHA256
Обратите внимание на разные представления: для HTTP-заголовков и параметров API требуются Base64 от бинарного хэша, для вывода в консоль привычнее hex. Не путайте форматы.
Multipart upload с checksum-algorithm, пошагово
Для крупных файлов (более 5 ГБ или когда вы хотите параллельную загрузку) используется multipart. Чтобы включить контрольные суммы:
- Инициализируйте multipart с указанием алгоритма,
- Передавайте для каждой части
x-amz-checksum-*, - При завершении отправьте контрольную сумму итогового объекта.
Пример командной последовательности (AWS CLI v2, SHA256):
# 1) Создаем multipart, сохраняем UploadId
aws s3api create-multipart-upload --bucket my-bucket --key big.iso --checksum-algorithm SHA256 --query UploadId --output text
# 2) Загружаем части с их SHA256 (Base64)
# Допустим, у нас части part1.bin, part2.bin одинакового размера
aws s3api upload-part --bucket my-bucket --key big.iso --part-number 1 --body part1.bin --upload-id <UPLOAD_ID> --checksum-sha256 $(openssl dgst -binary -sha256 part1.bin | base64)
aws s3api upload-part --bucket my-bucket --key big.iso --part-number 2 --body part2.bin --upload-id <UPLOAD_ID> --checksum-sha256 $(openssl dgst -binary -sha256 part2.bin | base64)
# Команда upload-part вернет ETag каждой части; их надо собрать в JSON для завершения
# 3) Считаем итоговый SHA256 всего файла (не конкатенации хэшей частей, а всего байтового потока)
openssl dgst -binary -sha256 big.iso | base64
# 4) Готовим JSON со списком частей и их ETag, плюс итоговая ChecksumSHA256
# Пример структуры (значения ETag вернуть из upload-part)
# {
# "Parts": [
# {"ETag": "\"<etag1>\"", "PartNumber": 1},
# {"ETag": "\"<etag2>\"", "PartNumber": 2}
# ]
# }
# Завершаем multipart и передаем итоговую сумму
aws s3api complete-multipart-upload --bucket my-bucket --key big.iso --upload-id <UPLOAD_ID> --multipart-upload file://parts.json --checksum-sha256 <base64-of-file-sha256>
Ключевые моменты:
- Итоговая контрольная сумма — это хэш всего файла, а не вычисление поверх хэшей частей.
- ETag итогового объекта в multipart не равен MD5 файла. Он будет иметь суффикс
-N, где N — число частей. - Для верификации используйте поля
Checksum*изHEAD/GETс--checksum-mode ENABLED(или соответствующую опцию SDK).

Как проверить объект после загрузки
Базовые варианты проверки:
- HEAD с включенными checksum: вернет
Checksum*и позволит сравнить с локальным значением. - GET с
--checksum-mode ENABLED: сервер вернет контрольную сумму в заголовках ответа; вы можете сверить ее с локально посчитанной по скачанному потоку. - ETag: используйте для условных запросов/кэша, но не для проверки содержимого, если не уверены, что это single-part без шифрования.
aws s3api head-object --bucket my-bucket --key big.iso --checksum-mode ENABLED --query '{ETag:ETag,ChecksumSHA256:ChecksumSHA256,PartsCount:PartsCount,Size:ContentLength}'
Выбор алгоритма: скорость vs надежность
CRC32/CRC32C быстры и хорошо подходят для детекта случайных ошибок передачи. CRC32C выгоден на современных CPU с аппаратным ускорением. SHA1 лучше CRC по коллизиям, но сегодня чаще предпочтителен SHA256 как стандарт де-факто для надежной верификации и унификации между системами.
Рекомендации на практике:
- Для долгосрочного хранителя и межплатформенной сверки берите SHA256.
- Для высокоскоростной внутренней репликации, где уже есть TLS и доп. контроль, можно рассмотреть CRC32C ради пропускной способности.
- Минимизируйте пересчет: хэшируйте поток один раз и переиспользуйте результат для записи и для локального каталога сумм.
Размер частей и производительность multipart
Балансируем три параметра: размер части, параллелизм и CPU на хэширование.
- Размер части: 64–128 МБ — хороший старт, чтобы уложиться в лимиты частей и держать разумный overhead на хэширование.
- Параллелизм: подбирайте по сетевому каналу и CPU. Часто 4–16 параллельных частей дают оптимум.
- Хэширование: используйте потоковое вычисление и, если позволяет язык/библиотека, параллельное чтение/хэш частей.
Важно: итоговый SHA256 всего файла все равно должен быть посчитан поверх полного потока. Это можно сделать либо заранее (до разрезания), либо после (по исходному файлу). Не пытайтесь «склеить» хэши частей — это другая математическая операция.
Если не хватает локальных ресурсов для параллельной заливки и хэширования, поднимите загрузочный агент на VDS и масштабируйте по CPU/сети под пиковую репликацию.
Про практическое влияние размера части и параллелизма на скорость см. разбор и пресеты в статье тюнинг multipart в rclone.
Что с S3-совместимыми хранилищами
Поддержка checksum-algorithm у различных провайдеров разная: где-то все четыре алгоритма, где-то только SHA256, а где-то опция еще не реализована. Типичные варианты поведения:
- Игнор заголовков
x-amz-checksum-*без ошибки, - Ошибка 4xx при указании неподдерживаемого алгоритма,
- Частичная поддержка: работает
PUT, но не возвращаютChecksum*вHEAD/GET.
Перед массовой миграцией или внедрением обязательных checksum выполните короткий эксперимент: загрузите небольшой файл с --checksum-algorithm и убедитесь, что HEAD возвращает соответствующее поле Checksum*.
Интеграция с инструментами синхронизации и бэкапов
Многие утилиты по умолчанию сравнивают ETag и размер. При multipart и/или шифровании сравнение по ETag даст ложные отличия. Корректные стратегии:
- Использовать режимы, в которых утилита сверяет контрольные суммы, а не ETag.
- Если checksum-algorithm недоступен на стороне S3, сохраняйте свою сумму в метаданных объекта (
x-amz-meta-sha256) или внешнем каталоге. Это менее удобно, но работает везде. - Для критичных данных делайте периодическую повторную верификацию: выборочно скачивайте и пересчитывайте хэш, сверяйте с сохраненным значением.
Частые ошибки и тонкости
- Hex vs Base64: HTTP-заголовки и поля API требуют Base64 от бинарного дайджеста (а не от hex-строки). Команда для SHA256:
openssl dgst -binary -sha256 file | base64. - ETag в multipart: значение вида
"deadbeef...-7"— это не MD5 файла. Не используйте для сверки содержимого. - SSE: при шифровании на стороне сервера ETag часто перестает быть хэшем содержимого. Для сверки полагайтесь на
Checksum*или свой каталог сумм. - Порядок частей: в
complete-multipart-uploadважно указать все части с корректнымиPartNumberи ETag. Пропуск или перестановка даст ошибку или повреждение результата. - Алгоритм на старых ЦП: SHA256 может стать узким местом CPU. Рассмотрите CRC32C с аппаратным ускорением, если бизнес-требования позволяют.
Диагностика: как понять, почему проверка не прошла
Если сервер вернул ошибку верификации при PUT или upload-part:
- Перепроверьте формат суммы (Base64) и соответствие выбранному алгоритму,
- Убедитесь, что именно тот файл/часть хэшируете (не перепутаны куски),
- Проверьте, не модифицирует ли клиент поток (например, перекодирование CRLF),
- На больших файлах — выключите антивирусные перехватчики/фильтры, которые могут менять поток чтения.
Практические пресеты
- Малые объекты (до 100 МБ):
PUTс--checksum-algorithm SHA256. Опционально--content-md5для совместимости. - Средние (100 МБ–5 ГБ): одиночный
PUTс SHA256; если канал нестабилен — переходите на multipart с частями 64–128 МБ. - Крупные (>5 ГБ): multipart + SHA256 на части и на итог. Параллелизм 8–16, мониторьте CPU.
- Нет поддержки checksum у провайдера: храните SHA256 в
x-amz-meta-sha256и ведите внешний каталог сумм для периодических сверок.
ETag и условные запросы
Даже если ETag не совпадает с MD5, он остается полезным для кэширования и условных запросов: If-None-Match для 304 Not Modified, If-Match для защиты от перезаписи. Подробнее о заголовках и сценариях см. ETag и условные запросы If-None-Match. Просто отделяйте задачи: ETag — про валидаторы кэша, Checksum* — про контроль целостности.
Резюме
В 2025 году правильная стратегия выглядит так:
- Не полагайтесь на ETag как на MD5, особенно при multipart и SSE.
- Используйте
checksum-algorithmи поляChecksum*для верификации на уровне API. - Подбирайте алгоритм под свои SLO: универсально — SHA256, максимально быстро — CRC32C.
- Тщательно реализуйте поддержку multipart: хэшируйте части, передавайте итоговую сумму объекта, проверяйте
HEADпосле загрузки. - Если провайдер не поддерживает явные checksum, применяйте метаданные и внешний каталог сумм.
Так вы получите корректную, переносимую и предсказуемую проверку данных в любом S3/Object Storage — без сюрпризов от ETag.


