OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

S3/Object Storage: ETag и checksum-algorithm в multipart upload на практике

ETag в S3 давно перестал быть «MD5 от файла». В статье — практический гид: когда ETag совпадает с MD5, что происходит в multipart upload, как включить checksum-algorithm (CRC32/CRC32C/SHA1/SHA256), проверить загрузку и не сломать синхронизацию.
S3/Object Storage: ETag и checksum-algorithm в multipart upload на практике

Если вы когда-то полагались на 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 не решает задачу контроля целостности всего объекта.

Сопоставление: ETag vs checksum в S3 и суффикс -N в multipart

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. Чтобы включить контрольные суммы:

  1. Инициализируйте multipart с указанием алгоритма,
  2. Передавайте для каждой части x-amz-checksum-*,
  3. При завершении отправьте контрольную сумму итогового объекта.

Пример командной последовательности (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).

Пошаговая последовательность aws s3api multipart с контрольными суммами

Как проверить объект после загрузки

Базовые варианты проверки:

  • 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}'
FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Выбор алгоритма: скорость 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.

Поделиться статьей

Вам будет интересно

Apache mod_cache: CacheQuickHandler, cache_disk vs cache_socache OpenAI Статья написана AI (GPT 5)

Apache mod_cache: CacheQuickHandler, cache_disk vs cache_socache

Если Apache — фронтенд или бэкенд для PHP/FCGI/прокси, mod_cache заметно разгружает приложение. Разбираем CacheQuickHandler, выбор ...
Docker BuildKit registry cache в CI: быстрые сборки на любом раннере OpenAI Статья написана AI (GPT 5)

Docker BuildKit registry cache в CI: быстрые сборки на любом раннере

Долгие Docker‑сборки в CI — классическая боль: свежие раннеры, мало диска и кэш каждый раз с нуля. Registry‑backed cache в BuildKi ...
MySQL 8: caching_sha2_password и TLS — безопасная аутентификация без сюрпризов OpenAI Статья написана AI (GPT 5)

MySQL 8: caching_sha2_password и TLS — безопасная аутентификация без сюрпризов

В MySQL 8 по умолчанию используется caching_sha2_password. Это повысило безопасность, но ломает старые клиенты без TLS. В статье — ...