这是否意味着我提供的MD5散列尚未经过验证?
不,它已经过验证了.
Amazon S3根据通过Content-MD5
标头发送的MD5校验和自动完成MD5校验和验证.
该值可以由SDK生成或作为PutObject
请求的一部分提供,但关键是,无论谁提供MD5摘要-验证都由AWS完成,如docs:
使用此标头时,为Amazon S3 checks the object against the provided MD5 value,如果不匹配,则为Amazon S3 returns an error.
如果提供的MD5Digest
是正确的(映射到Content-MD5
报头),则PutObjectRequest
成功,没有任何异常,表明MD5摘要已成功验证.
S3现在保证你上传的think是你上传的has.您的本地对象的MD5与S3-Great计算的MD5匹配.
现在,如果MD5Digest
不正确(或上传已损坏),.NET SDK将抛出此异常,错误代码为BadDigest
:
Amazon.S3.AmazonS3Exception: The Content-MD5 you specified did not match what we received.
个
这是所发生的事情的.NET版本,但请注意,SDK只是浮出了S3API的400 Bad Request
错误.
默认情况下,SDK会为您生成MD5摘要.如果满足以下任一条件,则不会为您计算该值:
你不需要提供你自己的价值.
或者,如果我将Checksum算法rithm
设置为Checksum算法rithm.SHA256
,则校验和由AWS计算
如果您将Checksum算法rithm
设置为所需的算法,AWS SDK将计算校验和.然后,计算出的校验和将包含在发送到Amazon S3的请求中.
但是,此校验和不能与Amazon S3在收到请求后生成的校验和混淆.Amazon S3使用其校验和与请求中发送的校验和进行交叉引用.
撇开MD5校验和验证不谈,S3 announced在2022年2月支持4种新的校验和算法,可与MD5完整性判断一起使用:
- CRC32:
x-amz-checksum-crc32
- CRC32C:
x-amz-checksum-crc32c
- SHA1:
x-amz-checksum-sha1
- SHA256:
x-amz-checksum-sha256
如上所述,这些校验和也可以由SDK计算或由用户提供,但是,Amazon S3再次对照提供的校验和值判断对象,如果它们不匹配,则Amazon S3返回错误.
格式与上面相同:如果您的CRC32/CRC32C/SHA1/SHA256校验和值不正确,您将得到一个错误代码为BadDigest
的异常,以及一条与您使用的任何校验和算法相关的消息.
Amazon.S3.AmazonS3Exception: The SHA256 you specified did not match the calculated checksum.
个
所有这些都与SDK无关.
SDK要么生成和发送生成的校验和值以及正确的头名称,要么只发送您手动为其提供正确头名称的校验和值,或者不发送头(不进行额外的校验和验证).
那么,ChecksumValidationStatus
是什么呢?
如果你看看S3API的response object--所有SDK基本上都是它的客户--它实际上并不在那里.关于额外的校验和算法,它是.NET-SDK-specific concept,与MD5校验和验证相关的是not.
该字段为not,与Amazon S3的S校验和值相关.这由S3响应表示,在.NET SDK的例子中:无异常=✅有效&已验证的校验和.
因此,假设我们上传对象payroll.txt
,其(伪)SHA256校验和值为a
.没有异常被抛出,所以我们知道S3已经验证了我的对象在传输中没有被损坏,因为它们计算的校验和值payroll.txt
也是a
.我们现在确信S3真的像最初预期的那样存储了payroll.txt
个.
在另一台设备上,我们通过.NET SDK发送GetObjectRequest
来下载payroll.txt
.我们知道S3真正存储的是payroll.txt
,但是我们怎么知道.NET SDK真的按预期下载了payroll.txt
呢?
这就是ChecksumValidationStatus
发挥作用的地方,这应该在GetObjectRequest
上进行判断.事实上,它甚至可以在PutObjectResponse
上访问,这对我来说似乎是一个漏洞百出的抽象概念.
这就是为什么即使我们指定了一个额外的SHA256校验和值进行验证,PutObjectResponse
的状态始终为NOT_VALIDATED
.SDK客户端甚至不会validate对象在PutObject
上的校验和,因此它甚至有意义拥有status.
有了这个字段,SDK就可以验证它是否下载了正确的对象&它是否在途中未被损坏.只要您已将请求的ChecksumMode
设置为ChecksumMode.ENABLED
,SDK就会获取和填充校验和字段,例如GetObjectResponse.ChecksumSHA256
.ChecksumMode
映射到x-amz-checksum-mode
标头.
当然,然后您可以手动验证这一点,但SDK试图帮助将ChecksumValidationStatus
的状态从PENDING_RESPONSE_READ
(其初始值POST GET)更改为SUCCESSFUL
或INVALID
(基于它生成的散列).
它只能在完全读取后生成下载对象的散列,即在ResponseStream
(标准.NET Stream
)关闭时.
你可以在基于公共源代码的ChecksumValidationStatus
enum的 comments 中看到这一点:
/// States for response checksum validation
public enum ChecksumValidationStatus
{
/// Set when the SDK did not perform checksum validation.
NOT_VALIDATED,
/// Set when a checksum was selected to be validated, but validation
/// will not completed until the response stream is fully read. At that point an exception
/// will be thrown if the checksum is invalid.
PENDING_RESPONSE_READ,
/// The checksum has been validated successfully during response unmarshalling.
SUCCESSFUL,
/// The checksum of the response stream did not match the header sent by the service.
INVALID
}
我做错了什么?
似乎有一个bug,一旦蒸汽完全关闭,GetRequest
上的验证状态永远不会从PENDING_RESPONSE_READ
更改为SUCCESSFUL
,甚至INVALID
.
我的示例代码演示了这一点:
using Amazon.S3;
using Amazon.S3.Model;
var bucketName = "xyz";
var filePath = $"{DateTimeOffset.Now.ToUnixTimeMilliseconds()}.txt";
await File.WriteAllTextAsync(filePath, "my-test-content");
var s3Client = new AmazonS3Client();
var putObject = new PutObjectRequest()
{
BucketName = bucketName,
Key = filePath,
FilePath = filePath,
ContentType = "application/txt",
Checksum算法rithm = Checksum算法rithm.SHA256,
};
Console.WriteLine($"Uploading object with key: {filePath}");
Console.WriteLine("---");
await s3Client.PutObjectAsync(putObject);
var getObject = new GetObjectRequest()
{
BucketName = bucketName,
Key = filePath,
ChecksumMode = ChecksumMode.ENABLED,
};
Console.WriteLine($"Getting object with key: {filePath}");
Console.WriteLine("---");
var getResponse = await s3Client.GetObjectAsync(getObject);
Console.WriteLine($"GET response SHA256: {getResponse.ChecksumSHA256}");
Console.WriteLine($"Response stream CanRead status (not closed): {getResponse.ResponseStream.CanRead}");
Console.WriteLine($"GET response checksum validation status: {getResponse.ResponseMetadata.ChecksumValidationStatus}");
Console.WriteLine("---");
Console.WriteLine($"Reading stream...");
using (var reader = new StreamReader(getResponse.ResponseStream))
{
var content = await reader.ReadToEndAsync();
Console.WriteLine($"Stream contents: {content}");
}
Console.WriteLine("---");
Console.WriteLine($"Response stream CanRead status (not closed): {getResponse.ResponseStream.CanRead}");
Console.WriteLine($"GET response checksum validation status: {getResponse.ResponseMetadata.ChecksumValidationStatus}");
输出:
Uploading object with key: 1702578364813.txt
---
Getting object with key: 1702578364813.txt
---
GET response SHA256: q7IK7CFDRfD5yHQ4kFLUm6PaH1qQVdUvT+1jR3NAw/4=
Response stream CanRead status (not closed): True
GET响应校验和验证状态:PENDING_RESPONSE_READ
---
Reading stream...
Stream contents: my-test-content
---
Response stream CanRead status (not closed): False
GET响应校验和验证状态:PENDING_RESPONSE_READ
第二条:
GET响应校验和验证状态:PENDING_RESPONSE_READ
应该是:
获取响应校验和验证状态:成功
我已经向AWS SDK for.NET团队表明了这一点,以澄清为什么该属性没有更新.当我有答复时,我会更新问题的.
总而言之:
Amazon S3可以 Select 性地验证对象的MD5校验和和/或一个额外的校验和值,以确保上传的对象的完整性
额外的校验和值可以是以下算法:MD5、CRC32、CRC32C、SHA1或SHA256
校验和值可以由用户提供,也可以由SDK根据SDK配置生成
S3 API在PutObject
请求上没有返回错误,表示S3已经成功验证了对象的校验和
SDK实现may提供了验证由API返回的校验和值的选项,只要SDK已经被配置为通过将x-amz-checksum-mode
设置为ENABLED
从S3获得校验和值
.NET SDK似乎有一个错误;AWS SDK for.NET团队现在正在调查这一问题