SignatureDoesNotMatch для запроса S3 PUT на предварительно назначенный URL - PullRequest
1 голос
/ 12 марта 2019

Я генерирую предварительно назначенный URL-адрес на стороне сервера, чтобы позволить моему клиентскому приложению загрузить файл непосредственно в корзину S3.Все работает нормально, если клиентское приложение не запущено на компьютере в часовом поясе, который технически на день опережает часы моего сервера.

Я могу воссоздать проблему локально, установив системные часы на часовой пояс на следующий день.

Вот как я генерирую предварительно назначенный URL-адрес с помощью .NET SDK (у меня изначально был DateTime.Now вместо UTCNow):

var request = new GetPreSignedUrlRequest
{
 BucketName = bucketName,
 Key = objectName,
 Verb = HttpVerb.PUT,
 Expires = DateTime.UtcNow.AddDays(5),
 ContentType = "application/octet-stream"
};

request.Headers["x-amz-acl"] = "bucket-owner-full-control";
request.Metadata.Add("call", JsonConvert.SerializeObject(call).ToString());

return client.GetPreSignedURL(request);

, а затем я использую этот предварительно назначенный URL-адрес вклиентское приложение, подобное этому:

using (var fileStream = new FileStream(recordingPath, FileMode.Open))
using (var client = new WebClient())
{
    HttpContent fileStreamContent = new StreamContent(fileStream);
    var bytes = await fileStreamContent.ReadAsByteArrayAsync();
    client.Headers.Add("Content-Type", "application/octet-stream");
    //include metadata in PUT request
    client.Headers.Add("x-amz-meta-call", JsonConvert.SerializeObject(Call));

    await client.UploadDataTaskAsync(new Uri(presignedUrl), "PUT", bytes);
}

Вот ошибка, которую я получаю от AWS:

<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>{access}</AWSAccessKeyId><StringToSign>....


В Fiddler запросы выглядят в основном идентично мне.

Работает:

PUT https://{bucketname}.s3.amazonaws.com/1c849c76-dd2a-4ff7-aad7-23ec7e9ddd45_encoded.opus?X-Amz-Expires=18000&x-amz-security-token={security_token}&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential={cred}&X-Amz-Date=20190312T021419Z&X-Amz-SignedHeaders=content-type;host;x-amz-acl;x-amz-meta-call;x-amz-security-token&X-Amz-Signature={sig} HTTP/1.1
x-amz-meta-call: {json_string}
x-amz-acl: bucket-owner-full-control
Content-Type: application/octet-stream
Host: {bucketname}.s3.amazonaws.com
Content-Length: 28289
Expect: 100-continue

{file}

Не работает:

PUT https://{bucketname}.s3.amazonaws.com/4cca3ec3-9f3f-4ba4-9d81-6336090610c0_encoded.opus?X-Amz-Expires=18000&x-amz-security-token={security_token}&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential={credentials}&X-Amz-Date=20190312T021541Z&X-Amz-SignedHeaders=content-type;host;x-amz-acl;x-amz-meta-call;x-amz-security-token&X-Amz-Signature={sig} HTTP/1.1
x-amz-meta-call: {json_string}
x-amz-acl: bucket-owner-full-control
Content-Type: application/octet-stream
Host: {bucketname}.s3.amazonaws.com
Content-Length: 18714
Expect: 100-continue


{file}

В обоих сценариях для предварительно назначенного URL-адреса создается один и тот же параметр x-amz-date.Я даже пытался разобрать параметр x-amz-date из URL и явно установить его в качестве заголовка в моем PUT, но это тоже не сработало.

Чего мне не хватает?

1 Ответ

0 голосов
/ 12 марта 2019

Таким образом, проблема оказалась в метаданных.В нашей настройке клиентское приложение отправляло строку JSON в наш API вместе с файлом для генерации предварительно назначенного URL.Мы использовали Json.net для десериализации в класс C #:

var call = JsonConvert.DeserializeObject<Call>(request.Params["metadata"]);

Очевидно, этот вызов преобразует любые временные метки в Json в местное время.Это означает, что мы подписали бы URL метками временных метаданных, локальными для сервера API, но фактически загрузили файл метками временных метаданных, локальными для клиента.Эта разница, почему рассчитанные подписи разные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...