【发布时间】:2017-02-15 21:35:06
【问题描述】:
我讨厌看到这样的回复:
我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。
我知道这个问题已在此处得到解答的版本:
SO - AWS S3 browser upload using HTTP POST gives invalid signature
而且我没有走运地跟踪了它的每一个细节,而且我可能遗漏了一些简单的东西。我正在使用 C# 生成策略和 v4 Aws 签名。这是政策代码:
var policyBuilder = new StringBuilder();
policyBuilder.AppendFormat("{{ \"expiration\": \"{0}\",\r\n", "2017-12-30T12:00:00.000Z");
policyBuilder.Append(" \"conditions\": [\r\n");
policyBuilder.Append(" [\"starts-with\", \"$key\", \"\"],\r\n");
policyBuilder.AppendFormat(" {{\"x-amz-credential\": \"{1}\"}},\r\n", <MyAccessKey>/20170214/us-east-2/s3/aws4_request));
policyBuilder.Append(" {\"x-amz-algorithm\": \"AWS4-HMAC-SHA256\"},\r\n");
policyBuilder.Append(" {\"x-amz-date\": \"20170214T000000Z\" }\r\n");
policyBuilder.Append(" ]\r\n}");
var policyString = policyBuilder.ToString();
var policyStringBytes = Encoding.UTF8.GetBytes(policyString);
return Convert.ToBase64String(policyStringBytes);
这是用于生成签名的代码:
static byte[] HmacSHA256(String data, byte[] key)
{
String algorithm = "HmacSHA256";
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(algorithm);
kha.Key = key;
return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
}
static byte[] GetSignatureKey(String key, String dateStamp, String regionName, String serviceName)
{
byte[] kSecret = Encoding.UTF8.GetBytes(("AWS4" + key).ToCharArray());
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256("aws4_request", kService);
return kSigning;
}
public static string ToHexString(byte[] data, bool lowercase)
{
var sb = new StringBuilder();
for (var i = 0; i < data.Length; i++)
{
sb.Append(data[i].ToString(lowercase ? "x2" : "X2"));
}
return sb.ToString();
}
将这一切结合在一起的方法:
public string GetS3PolicySignatureV4(string policy)
{
byte[] signingKey = GetSignatureKey(<MySecretKey>, "20170214T000000Z", "us-east-2", "s3");
byte[] signature = HmacSHA256(policy, signingKey);
return AWS4SignerBase.ToHexString(signature, true);
}
这里是html表单:
<form action="http://<BucketName>.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
<input type="hidden" name="key" value="<FileKey>" />
<input type="hidden" name="x-amz-credential" value="<MyAccessKey>/20170214/us-east-2/s3/aws4_request"/>
<input type="hidden" name="x-amz-algorithm" value="AWS4-HMAC-SHA256" />
<input type="hidden" name="x-amz-date" value="20170214T000000Z" />
<input type="hidden" name="policy" value='<Base64PolicyResult>' />
<input type="hidden" name="x-amz-signature" value="<GenerateSignature>" />
File:
<input type="file" name="file" /> <br />
<input type="submit" name="submit" value="Upload to Amazon S3" />
</form>
我已验证示例策略导致此示例:
AWS - Examples: Browser-Based Upload using HTTP POST (Using AWS Signature Version 4)
以及使用提供的参数和密钥与示例匹配的结果签名。但是当我尝试 POST 到 S3 时,我总是得到可怕的响应。
【问题讨论】:
-
我想我找到了沃尔多。在示例中,您的策略文档中缺少
{"bucket": "sigv4examplebucket"},。 -
@Michael-sqlbot 我也尝试过使用策略中的“桶”,实际上该示例中包含的所有策略选项。根据这个docs.aws.amazon.com/AmazonS3/latest/API/…,策略中唯一需要的元素是:x-amz-algorithm、x-amz-credential 和 x-amz-date。根据计算签名的方法(我从这里得到:docs.aws.amazon.com/general/latest/gr/…),策略的内容应该与计算签名无关。
-
什么?!不。这就是创建 签名密钥 的算法——而不是签名。您使用签名密钥创建一个签名of 策略的 base64 表示。策略中的单个字节不同会极大地改变签名。签名保护策略不被篡改,然后策略确定请求是否有效,因为表单与策略匹配。
-
@Michael-sqlbot 对,我混淆了术语。策略是签名密钥,用于使用相同的信息计算签名,即密钥、日期、区域和服务。但是,策略中不需要存储桶来计算签名。一旦 Aws 与签名匹配,然后读取策略中的值,它就会因为没有存储桶而犹豫不决,我试图解决的问题是签名不匹配。我只是想通了这个问题。下一个答案...
标签: c# amazon-web-services amazon-s3