Azure SDK Storage Content Validation変更点|MD5+CRC64競合の影響と対応

2026年5月5日にマージされた Azure SDK for Java の Storage Content Validation 更新では、Azure Storage Blob のトランザクションアップロード時に、呼び出し側が指定した Content-MD5 と CRC64 または AUTO などのコンテンツ検証アルゴリズムを同時に設定した場合の扱いが変わりました。結論から言うと、「MD5とCRC64を同時に使えるようになった」わけではありません。これまでSDK側で早期に IllegalArgumentException として拒否していた競合を、今後はAzure Storageサービス側に送信し、サービスの 400 Bad Request として扱う方向に変わります。(GitHub)

この変更で確認すべきなのは、アップロード処理そのものよりも、例外処理・テスト・監視ログ・リトライ制御です。特に、IllegalArgumentException を捕捉して入力エラーとして処理しているJavaアプリケーションでは、SDK更新後に BlobStorageException の 400 として扱う必要が出る可能性があります。(GitHub)

目次

Azure SDKのStorage Content Validation変更で何が変わったのか

今回の変更は、Azure SDK for Java の azure-storage-blob におけるコンテンツ検証の挙動を、Azure Storage REST APIのエラー仕様に近づけるものです。

Azure Storageでは、Content-MD5 と x-ms-content-crc64 の両方が同じリクエストに存在する場合、リクエストは 400 Bad Request で失敗します。これはPut BlobやPut BlockなどのREST APIドキュメントにも明記されています。(Microsoft Learn)

今回のPRでは、SDK側でこの組み合わせを事前に拒否する処理が一部削除されました。対象は、呼び出し側が contentMd5 を明示的に指定し、同時に ContentValidationAlgorithm.CRC64 または AUTO を設定するようなケースです。PRの説明では、これらの呼び出しをAzure Storageへ送信し、サービス側が Content-MD5 と x-ms-content-crc64 の競合を検出して 400 Bad Request を返す形に変更するとされています。(GitHub)

観点変更前変更後
競合の検出場所Azure SDKクライアント側Azure Storageサービス側
主な例外IllegalArgumentExceptionBlobStorageException
HTTPリクエスト送信前に失敗サービスへ送信される
ステータスコードなし400 Bad Request
開発者が見直す箇所入力チェック中心例外処理、テスト、監視、リトライ

ここで重要なのは、エラーの意味は変わらないが、エラーの出方が変わるという点です。MD5とCRC64の競合は依然として不正な組み合わせです。ただし、SDKがローカルで止めるのではなく、Azure StorageのREST APIと同じ意味づけでサービスエラーとして返すようになります。

影響を受ける可能性がある処理

PRで変更対象として確認できるのは、Blob Storageのトランザクションアップロード系APIです。ファイル全体をアップロードする処理だけでなく、ブロック、追加ブロック、ページBLOBのアップロードにも影響する可能性があります。変更ファイルには BlockBlobAsyncClient、AppendBlobAsyncClient、PageBlobAsyncClient、および同期・非同期アップロードのテストが含まれています。(GitHub)

対象処理代表的なオプション確認すべきポイント
ブロックBLOBの単発アップロードBlockBlobSimpleUploadOptionssetContentMd5() と setContentValidationAlgorithm() を同時に使っていないか
ステージブロックBlockBlobStageBlockOptionsブロック単位のMD5とCRC64設定が重複していないか
追加BLOBへの追記AppendBlobAppendBlockOptions追記処理でMD5を付けつつCRC64/AUTOを有効化していないか
ページBLOBへのページ書き込みPageBlobUploadPagesOptionsページ単位の検証設定が競合していないか
テストコードJUnit、StepVerifierなどIllegalArgumentException 前提のテストを BlobStorageException 前提に変更する必要があるか

一方で、次のようなケースでは直接の影響は限定的です。

  • Content-MD5 だけを設定している
  • CRC64 または AUTO だけを設定している
  • コンテンツ検証アルゴリズムを明示的に使っていない
  • まだ該当変更を含むSDKバージョンへ更新していない
  • Azure SDK for Java以外の言語SDKを使っており、同等の変更が入っていない

なお、このPRは feature/storage/content-validation ブランチへマージされた変更として確認できます。実際に利用中の azure-storage-blob パッケージへ反映されているかは、導入しているSDKバージョンとリリースノートで確認してください。(GitHub)

「Content-MD5」と「CRC64」を同時に設定してはいけない理由

Content-MD5 と x-ms-content-crc64 は、どちらも転送中のデータ整合性を確認するための仕組みです。Azure StorageのREST APIでは、同じリクエストで両方のヘッダーが存在すると 400 Bad Request になります。つまり、SDKの挙動が変わっても、サービス仕様としては「どちらか一方を選ぶ」必要があります。(Microsoft Learn)

また、Java SDKの setContentMd5(byte[] contentMd5) は、コンテンツのMD5ハッシュを設定し、転送中に到着した内容と比較するためのものです。APIリファレンスでは、このMD5はBLOBに保存されるものではなく、ハッシュが一致しない場合は操作が失敗すると説明されています。(Microsoft Learn)

実務では、次のように判断すると安全です。

やりたいこと推奨される考え方
転送中の破損検知を行いたいContent-MD5 または CRC64/AUTO のどちらか一方を使う
REST APIと同じエラー挙動で扱いたいサービス側の 400 Bad Request を前提に例外処理する
既存コードでMD5を明示指定している新しいコンテンツ検証アルゴリズムを追加する前に競合を確認する
SDKに自動検証を任せたいAUTO を使う場合、別途 Content-MD5 を付けていないか確認する
セキュリティ目的で改ざん対策をしたいMD5やCRC64ではなく、認証、認可、TLS、署名、アクセス制御を設計する

特に注意したいのは、MD5を「セキュリティ対策」として扱うケースです。ここでのMD5やCRC64は、主に転送中の整合性確認のための仕組みです。アクセス制御や改ざん耐性を担保する仕組みとは役割が異なります。

既存コードで確認すべきポイント

Azure SDKを使ってBlobへアップロードしているJavaアプリケーションでは、まずコードベース内で次の組み合わせを検索してください。

setContentMd5(...)
setContentValidationAlgorithm(...)

この2つが同じアップロードオプションに対して設定されている場合、該当SDKの変更後は、従来のようにSDK内部で IllegalArgumentException が発生するのではなく、Azure Storageへリクエストが送られ、サービス側の 400 として返る可能性があります。

変更前の処理でありがちな実装

try {
    client.uploadWithResponse(options, timeout, context);
} catch (IllegalArgumentException e) {
    // MD5とCRC64の競合など、SDK側の入力エラーとして処理
    log.warn("Invalid upload options: {}", e.getMessage());
}

このような実装では、SDK更新後に同じ競合を捕捉できない可能性があります。なぜなら、エラーがSDKのローカル検証ではなく、サービス応答として返るためです。

変更後を見据えた例外処理

try {
    client.uploadWithResponse(options, timeout, context);
} catch (BlobStorageException e) {
    if (e.getStatusCode() == 400
        && e.getMessage() != null
        && e.getMessage().contains("x-ms-content-crc64")) {
        log.warn("Conflicting content validation headers: {}", e.getMessage());
        // 入力設定の競合として扱う
        return;
    }

    throw e;
}

BlobStorageException にはレスポンスのステータスコードを取得する getStatusCode() が用意されています。サービス側の 400 として返るケースでは、ステータスコードやサービスメッセージを使って、認可エラーや存在しないリソースのエラーとは分けて扱うのが実務上安全です。(Microsoft Learn)

ただし、メッセージ文字列だけに強く依存すると、将来の文言変更で判定が壊れる可能性があります。基本は 400、利用できる場合はエラーコード、補助的にメッセージを確認する形にしてください。

テストで修正が必要になりやすい箇所

今回のPRでは、従来 IllegalArgumentException を期待していたテストが、サービス側の BlobStorageException と 400 を期待するテストへ置き換えられています。非同期アップロードテストでは BlobStorageException を検証し、ステータスコードが 400 であること、メッセージに Both x-ms-content-crc64 header and Content-MD5 header are present. が含まれることを確認する形になっています。(GitHub)

既存のテストでは、次のような観点で見直してください。

テスト観点変更前の想定見直し後の想定
例外型IllegalArgumentExceptionBlobStorageException
通信有無通信しない通信する可能性がある
モックSDK内部の例外をモックHTTP 400レスポンスをモック
非同期テストverifyErrorMatchesでローカル例外を検証verifyErrorSatisfiesなどでサービス例外を検証
ログ検証入力エラーのログStorageサービスエラーのログ

単体テストでHTTP通信を発生させたくない場合は、アプリケーション側で独自の事前チェックを残す選択肢もあります。たとえば、社内ルールとして「MD5とCRC64/AUTOの同時指定は禁止」と明示し、SDKへ渡す前に設定値を検査する方法です。

boolean hasMd5 = options.getContentMd5() != null;
boolean usesCrc64 = options.getContentValidationAlgorithm() == ContentValidationAlgorithm.CRC64
    || options.getContentValidationAlgorithm() == ContentValidationAlgorithm.AUTO;

if (hasMd5 && usesCrc64) {
    throw new IllegalStateException("Content-MD5 and CRC64/AUTO must not be set together.");
}

このようなアプリケーション側のチェックは、SDK変更に依存せず、設定ミスを早い段階で検出できます。ただし、SDKやサービスの公式挙動そのものを置き換えるものではありません。運用上「リクエストを送る前に止めたい」場合の補助策として考えるとよいでしょう。

監視・ログ・リトライ設定で注意すること

この変更は、アプリケーションの監視にも影響します。これまでローカル例外として記録されていた設定ミスが、Azure Storageの 400 Bad Request として記録される可能性があるためです。

特に、次のような監視ルールがある場合は見直しが必要です。

監視・運用項目注意点
4xxエラー率のアラートSDK更新後に設定ミスがStorageの400として増える可能性がある
リトライ処理400 は通常、再試行しても成功しない設定エラーとして扱う
障害分類Storage障害ではなく、リクエストヘッダー競合として分類する
APMのエラー集計IllegalArgumentException から BlobStorageException に分類が変わる
サポート調査リクエストID、時刻、ステータスコード、該当ヘッダー設定を残す

とくにリトライは重要です。MD5とCRC64の同時指定による 400 は、ネットワークの一時障害ではありません。アプリケーション側の設定を変えない限り、再試行しても同じエラーになります。カスタムリトライを実装している場合は、400 を無条件で再試行しないように確認してください。

移行時のチェックリスト

SDK更新前後で混乱しないために、次の順番で確認すると効率的です。

手順確認内容判断基準
1利用中のSDKバージョンを確認該当PRの変更を含むか
2setContentMd5 の利用箇所を検索明示的にMD5を付けているアップロードがあるか
3setContentValidationAlgorithm の利用箇所を検索CRC64 または AUTO を同時指定していないか
4例外処理を確認IllegalArgumentException のみ捕捉していないか
5テストを確認期待例外が古いSDK挙動に依存していないか
6監視ルールを確認新たな 400 Bad Request を設定ミスとして識別できるか
7リトライ設定を確認競合による 400 を再試行し続けないか

この変更は、コードを大きく書き換える必要があるタイプの破壊的変更とは限りません。しかし、例外型に依存した処理やテストでSDK内部の早期失敗を前提にしている処理では、影響が出やすくなります。

実務での推奨対応

最も安全な対応は、アップロード処理の設計として「MD5を使うのか、CRC64/AUTOを使うのか」を明確に分けることです。

新規実装では、次のようなルールを決めておくと、将来のSDK変更にも強くなります。

方針向いているケース
Content-MD5 を明示指定する既存システムがMD5値を事前計算しており、互換性を維持したい
CRC64 を使うAzure Storageのトランザクション検証としてCRC64を明示的に使いたい
AUTO を使うSDK側のコンテンツ検証機能に任せたい
どちらも使わない小規模・低リスクの転送で、標準の通信とサービス応答で十分な場合

既存システムでは、まずMD5の指定理由を確認してください。単に過去のサンプルコードを踏襲しているだけなら、CRC64/AUTO導入時に削除できる場合があります。逆に、外部システムとの整合性確認でMD5値が必要な場合は、CRC64/AUTOを追加しないほうが安全です。

まとめ:次にやるべきこと

今回のAzure SDK Storage Content Validation更新は、MD5とCRC64の競合を許可する変更ではなく、競合検出をSDK側からAzure Storageサービス側へ寄せる変更です。そのため、同時指定したリクエストは引き続き 400 Bad Request で失敗します。(GitHub)

対応としては、まず setContentMd5() と setContentValidationAlgorithm() の同時利用がないかを確認してください。該当箇所がある場合は、MD5・CRC64・AUTOのどれを使うかを決め、不要な設定を削除します。あわせて、IllegalArgumentException 前提の例外処理やテストを、BlobStorageException と 400 を扱える形に見直すことが重要です。

SDKを更新する前にこの確認を済ませておけば、リリース後に「アップロードが突然Storageの400エラーとして記録される」といった混乱を避けられます。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次