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サービス側 |
| 主な例外 | IllegalArgumentException | BlobStorageException |
| HTTPリクエスト | 送信前に失敗 | サービスへ送信される |
| ステータスコード | なし | 400 Bad Request |
| 開発者が見直す箇所 | 入力チェック中心 | 例外処理、テスト、監視、リトライ |
ここで重要なのは、エラーの意味は変わらないが、エラーの出方が変わるという点です。MD5とCRC64の競合は依然として不正な組み合わせです。ただし、SDKがローカルで止めるのではなく、Azure StorageのREST APIと同じ意味づけでサービスエラーとして返すようになります。
影響を受ける可能性がある処理
PRで変更対象として確認できるのは、Blob Storageのトランザクションアップロード系APIです。ファイル全体をアップロードする処理だけでなく、ブロック、追加ブロック、ページBLOBのアップロードにも影響する可能性があります。変更ファイルには BlockBlobAsyncClient、AppendBlobAsyncClient、PageBlobAsyncClient、および同期・非同期アップロードのテストが含まれています。(GitHub)
| 対象処理 | 代表的なオプション | 確認すべきポイント |
|---|---|---|
| ブロックBLOBの単発アップロード | BlockBlobSimpleUploadOptions | setContentMd5() と 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)
既存のテストでは、次のような観点で見直してください。
| テスト観点 | 変更前の想定 | 見直し後の想定 |
|---|---|---|
| 例外型 | IllegalArgumentException | BlobStorageException |
| 通信有無 | 通信しない | 通信する可能性がある |
| モック | 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の変更を含むか |
| 2 | setContentMd5 の利用箇所を検索 | 明示的にMD5を付けているアップロードがあるか |
| 3 | setContentValidationAlgorithm の利用箇所を検索 | 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エラーとして記録される」といった混乱を避けられます。

コメント