当我设置包含"+"的响应标头覆盖时,为什么我的S3预签名请求无效?

Rag*_*esh 6 c# amazon-s3

我正在使用Amazon .NET SDK生成预先签名的URL,如下所示:

public System.Web.Mvc.ActionResult AsActionResult(string contentType, string contentDisposition)
{
    ResponseHeaderOverrides headerOverrides = new ResponseHeaderOverrides();
    headerOverrides.ContentType = contentType;
    if (!string.IsNullOrWhiteSpace(contentDisposition))
    {
        headerOverrides.ContentDisposition = contentDisposition;
    }

    GetPreSignedUrlRequest request = new GetPreSignedUrlRequest()
               .WithBucketName(bucketName)
               .WithKey(objectKey)
               .WithProtocol(Protocol.HTTPS)
               .WithExpires(DateTime.Now.AddMinutes(6))
               .WithResponseHeaderOverrides(headerOverrides);

    string url = S3Client.GetPreSignedURL(request);

    return new RedirectResult(url, permanent: false);
}
Run Code Online (Sandbox Code Playgroud)

这非常有效,除非我的中contentType包含一个+.当我尝试获取SVG文件(例如,获取内容类型)时会发生这种情况image/svg+xml.在这种情况下,S3会抛出SignatureDoesNotMatch错误.

错误消息显示StringToSign如下:

GET 1234567890 /blah/blabh/blah.svg?response-content-disposition=filename="blah.svg"&response-content-type=image/svg xml
Run Code Online (Sandbox Code Playgroud)

请注意,response-content-type中有一个空格,现在它image/svg xml代替的是image/svg+xml.在我看来,这就是导致问题的原因,但是解决这个问题的正确方法是什么?

我应该编码我的内容类型吗?用引号或其他东西括起来?文档没有说明这一点.

Rag*_*esh 5

更新

自SDK的1.4.1.0版本起,此错误已得到修复.


解决方法

这是AWS SDK中已确认的错误,因此在他们发布修复程序之前我会使用此hack来使事情正常工作:

在响应标头中准确指定内容类型的样子.因此,如果您希望S3返回内容类型image/svg+xml,请将其设置为:

ResponseHeaderOverrides headerOverrides = new ResponseHeaderOverrides();
headerOverrides.ContentType = "image/svg+xml";
Run Code Online (Sandbox Code Playgroud)

现在,继续像往常一样生成预先签名的请求:

GetPreSignedUrlRequest request = new GetPreSignedUrlRequest()
  .WithBucketName(bucketName)
  .WithKey(objectKey)
  .WithProtocol(Protocol.HTTPS)
  .WithExpires(DateTime.Now.AddMinutes(6))
  .WithResponseHeaderOverrides(headerOverrides);

string url = S3Client.GetPreSignedURL(request);
Run Code Online (Sandbox Code Playgroud)

最后,使用您的内容类型的正确URL编码值"修复"生成的URL:

url = url.Replace(contentType, HttpUtility.UrlEncode(contentType));
Run Code Online (Sandbox Code Playgroud)

是的,这是一个肮脏的解决方法,但是,嘿,它对我有用!:)