関連用語

ETag (Entity Tag)

HTTPプロトコルで定義されているレスポンスヘッダの一つで、リソースの特定バージョンを識別するための文字列

出典: RFC 7232 - Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests

“An entity-tag is an opaque validator for differentiating between multiple representations of the same resource”

※ここでのリソース: HTTPでアクセス可能なあらゆるコンテンツのこと

具体例(S3以外):

  • Webページの HTML ファイル(https://example.com/index.html
  • REST APIのレスポンス(https://api.example.com/users/123
  • 画像ファイル(https://cdn.example.com/logo.png

ETagの使われ方の例

ブラウザがWebページをキャッシュする場面を考える

1回目のリクエスト:
  ブラウザ → サーバー: GET /index.html
  サーバー → ブラウザ: 200 OK, ETag: "abc123", (HTMLの中身)
  ブラウザ: HTMLをキャッシュに保存、ETagも記憶

2回目のリクエスト:
  ブラウザ → サーバー: GET /index.html, If-None-Match: "abc123"
  サーバー: ETagが同じ = 内容変わってない
  サーバー → ブラウザ: 304 Not Modified(本文なし)
  ブラウザ: キャッシュを使う → 通信量削減

S3においては、オブジェクトの内容が変わるとETagも変わる。ただしメタデータの変更では変わらない

出典: Common response headers - Amazon Simple Storage Service

“The ETag reflects changes only to the contents of an object, not its metadata.”

MD5 (Message Digest 5)

任意長のデータから128ビット(16進数で32文字)の固定長ハッシュ値を生成するハッシュアルゴリズム(ハッシュ関数)の名前

関連用語:

  • MD5: アルゴリズム自体の名前
  • MD5ハッシュ値 / MD5ダイジェスト: MD5アルゴリズムを適用して得られる出力値

具体例:

入力: "hello"
MD5ハッシュ値: 5d41402abc4b2a76b9719d911017c592

入力: "hello "  ← スペース1つ追加しただけ
MD5ハッシュ値: 1a77a8341bddc4b45418f9c30e7102b4  ← 全く違う値になる

用途:

  • データの整合性検証(転送中に破損していないか確認)
  • ファイルの同一性チェック

具体例(整合性検証):

送信側: 100MBのファイルを送る、MD5は "abc123..."
受信側: 受け取ったファイルのMD5を計算 → "abc123..." なら破損なし

チェックサム (Checksum)

データの整合性を検証するために計算される値。データが変更されると値も変わるため、転送エラーや破損の検出に使用される

具体例:

ファイルをダウンロードするとき、配布元が「SHA-256: 7f83b1657...」と記載
→ ダウンロード後に自分で計算して一致すれば、正しくダウンロードできたと確認できる

S3がサポートするチェックサムアルゴリズム:

出典: Checking object integrity in Amazon S3

“When uploading, copying, or managing your data, you can choose from several supported checksum algorithms: CRC-64/NVME (CRC64NVME), CRC-32 (CRC32), CRC-32C (CRC32C), SHA-1 (SHA1), SHA-256 (SHA256), MD5 (MD5)”

  • CRC-64/NVME(デフォルト)
  • CRC-32
  • CRC-32C
  • SHA-1
  • SHA-256
  • MD5

ETagの計算方法

S3のETagは「常にMD5ハッシュ値」ではない。アップロード方法と暗号化方式によって変わる

出典: Common response headers - Amazon Simple Storage Service

“The ETag might or might not be an MD5 digest of the object data. Whether or not it is depends on how the object was created and how it is encrypted”

ETag = MD5ハッシュ値 になるケース

条件: 以下の両方を満たす場合のみ

  1. 単一のPUT操作でアップロード(マルチパートではない)
  2. 暗号化なし、または SSE-S3 を使用

出典: Common response headers - Amazon Simple Storage Service

“Objects that are plaintext or encrypted by server-side encryption with Amazon S3 managed keys (SSE-S3) have ETags that are an MD5 digest of their data.”

具体例:

$ echo "hello" > test.txt
$ md5 test.txt
MD5 (test.txt) = b1946ac92492d2347c6235b4d2611184
 
$ aws s3 cp test.txt s3://my-bucket/test.txt
$ aws s3api head-object --bucket my-bucket --key test.txt
{
    "ETag": "\"b1946ac92492d2347c6235b4d2611184\"",
    ...
}
 MD5と一致

ETag ≠ MD5ハッシュ値 になるケース

ケース1: SSE-KMS または SSE-C で暗号化

出典: Common response headers - Amazon Simple Storage Service

“Objects encrypted by server-side encryption with customer-provided keys (SSE-C) or AWS Key Management Service (AWS KMS) keys (SSE-KMS) have ETags that are not an MD5 digest of their object data.”

ケース2: マルチパートアップロード

出典: Common response headers - Amazon Simple Storage Service

“Objects created by either the Multipart Upload or Upload Part Copy operation have ETags that are not MD5 digests, regardless of the method of encryption.”

ETagの形式が変わる:

通常:        "d41d8cd98f00b204e9800998ecf8427e"
マルチパート: "d41d8cd98f00b204e9800998ecf8427e-3"
                                            ↑ パート数

マルチパート時のETag計算式:

ETag = MD5( MD5(Part1) + MD5(Part2) + ... + MD5(PartN) ) - N

具体例(3パートの場合):
  Part1のMD5: aaa...
  Part2のMD5: bbb...
  Part3のMD5: ccc...
  
  ETag = MD5( aaa... + bbb... + ccc... ) + "-3"

出典: All about AWS S3 ETags - Teppen.io

S3へのアップロードが正常に完了したか検証する方法

Content-MD5ヘッダーとは

HTTPリクエストのヘッダーの一つで、リクエストボディのMD5ハッシュ値をBase64エンコードした文字列を格納する

出典: RFC 1864 - The Content-MD5 Header Field

“The Content-MD5 header field is an MD5 digest of the entity body”

具体例:

ファイルの中身: "hello"
MD5ハッシュ値(バイナリ): 0x5d41402abc4b2a76b9719d911017c592
Base64エンコード: XUFAKrxLKna5cZ2REBfFkg==

HTTPリクエスト:
  PUT /test.txt HTTP/1.1
  Content-MD5: XUFAKrxLKna5cZ2REBfFkg==
  
  hello

用途: 送信中にデータが破損していないかをサーバー側で検証できる

方法1: Content-MD5ヘッダーを使う(アップロード時の検証)

アップロードリクエストに Content-MD5 ヘッダーを付けると、S3側で検証してくれる

# ローカルでMD5を計算してBase64エンコード
$ MD5_BASE64=$(openssl dgst -md5 -binary test.txt | base64)
$ echo $MD5_BASE64
XUFAKrxLKna5cZ2REBfFkg==
 
# Content-MD5ヘッダー付きでアップロード
$ aws s3api put-object \
    --bucket my-bucket \
    --key test.txt \
    --body test.txt \
    --content-md5 "$MD5_BASE64"

動作:

クライアント → S3: ファイル + Content-MD5: "XUFAKrxLKna5cZ2REBfFkg=="
S3: 受信したファイルのMD5を計算
    一致 → 200 OK、オブジェクト保存
    不一致 → 400 BadDigest エラー、保存しない

出典: PutObject - Amazon Simple Storage Service

“To ensure that data is not corrupted traversing the network, use the Content-MD5 header. When you use this header, Amazon S3 checks the object against the provided MD5 value and, if they do not match, Amazon S3 returns an error.”

注意: Directory buckets(S3 Express One Zone)では使えない

方法2: ETagで検証(アップロード後の検証)

アップロード後にETagとローカルのMD5を比較する

# アップロード
$ aws s3 cp test.txt s3://my-bucket/test.txt
 
# ローカルのMD5(16進数)
$ LOCAL_MD5=$(md5 -q test.txt)
$ echo $LOCAL_MD5
5d41402abc4b2a76b9719d911017c592
 
# S3のETag取得
$ S3_ETAG=$(aws s3api head-object --bucket my-bucket --key test.txt --query ETag --output text | tr -d '"')
$ echo $S3_ETAG
5d41402abc4b2a76b9719d911017c592
 
# 比較
$ [ "$LOCAL_MD5" = "$S3_ETAG" ] && echo "OK" || echo "NG"
OK

※ マルチパートアップロードやSSE-KMS/SSE-Cの場合は単純比較できない

方法3: チェックサムアルゴリズムを指定(推奨)

2024年12月以降、S3はデフォルトでCRCチェックサムを計算・保存するようになった

出典: Amazon S3 adds new default data integrity protections

# SHA-256チェックサムを指定してアップロード
$ aws s3api put-object \
    --bucket my-bucket \
    --key test.txt \
    --body test.txt \
    --checksum-algorithm SHA256
 
# アップロード後にチェックサムを取得
$ aws s3api get-object-attributes \
    --bucket my-bucket \
    --key test.txt \
    --object-attributes Checksum
{
    "Checksum": {
        "ChecksumSHA256": "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="
    }
}

出典: Checking object integrity in Amazon S3


  • 単純なケース: Content-MD5 ヘッダーが手軽
  • マルチパートや暗号化を使う場合: --checksum-algorithm を指定する方法が確実
  • ETag比較は条件付きでしか使えないので、新規実装では避けた方がいい