Как заставить клиента отправлять правильный sha256 в качестве ключа файла при загрузке s3?(назначенный URL) - PullRequest
0 голосов
/ 24 апреля 2019

Мне нужно создать подписанный URL для загрузки файла в корзину s3. Ключ файла s3 должен быть его sha256 хешем.

Тогда возникает вопрос: как я могу убедиться, что клиент отправляет действительный хэш? Я создаю подписанный URL-адрес в своей функции лямбда-выражения и не пропускаю через нее файл, поэтому лямбда-выражение, конечно, не может вычислить хэш.

Я думаю, что могу добиться этого, используя 2 шага:

  1. Принудительно отправляет клиенту свои расчетные sha256 с загрузкой. Исходя из спецификации, я предполагаю, что это будет автоматически проверено при предоставлении его в заголовке x-amz-content-sha256.

  2. Заставить клиента отправлять тот же хэш лямбде, чтобы я мог заставить его быть ключом.

Сначала я попробовал это:

s3.getSignedUrl('putObject', { Key: userProvidedSha256 }, callback)

Я попытался добавить условие типа { header: { 'X-Amz-Content-Sha256': userProvidedSha256 } }.

Но я не нашел способа добавить такое определение, чтобы оно фактически заставляло клиента отправлять заголовок X-Amz-Content-Sha256.

Кроме того, я бы применил тот же подход для обеспечения фиксированного требуемого заголовка Content-Length (клиент отправляет желаемую длину на сервер, там мы его подписываем), но не уверен, что это сработает из-за этой проблемы .

Поскольку я обнаружил, что s3.createPresignedPost также позволяет мне ограничивать максимальный размер вложения и выглядит более гибким, я пошел по этому пути:

const signPostFile = () => {
  const params = {
    Fields: {
      key: userProvidedSha256
    },
    Expires: 86400,
    Conditions: [
      ['content-length-range', 0, 10000000],
      { 'X-Amz-Content-Sha256': userProvidedSha256]
    ]
  }

  s3.createPresignedPost(params, callback)
}

Но пока это работает (это заставляет клиента отправлять принудительный заголовок sha256, и заголовок передается, см. Журнал запросов ниже), похоже, что клиент теперь должен добавить x-amz-content-sha256 в поля формы, а не заголовок Это выглядит так, как задумано, но ясно, что s3 не будет сравнивать представленный файл с предоставленным sha256: любой файл, который я добавляю в форму, успешно загружен, даже если sha256 не соответствует.

Есть ли какие-либо предположения о том, что не так или как еще можно применить условие sha256, одновременно ограничивая длину содержимого?

Обновление: я использую подпись v4, и я попробовал политику S3 Deny для этого условия:

Condition:
  StringEquals:
    s3:x-amz-content-sha256: UNSIGNED-PAYLOAD

Соответствующий журнал запросов на отправку файла, содержащего строку «hello world»:


----------------------------986452911605138616518063
Content-Disposition: form-data; name="X-Amz-Content-Sha256"

b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
----------------------------986452911605138616518063
Content-Disposition: form-data; name="key"

b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9

1 Ответ

0 голосов
/ 26 апреля 2019

Насколько мне известно S3 не предоставляет sha256 по умолчанию. Однако, слушая события S3, вы можете реализовать лямбда-функцию, которая делает это автоматически для вас. Вот совет, который приходит на ум:

  1. Клиент запрашивает подписанный URL-адрес S3 на основе предоставленной пользователем sha256
  2. Клиент загружает файл, используя подписанный URL
  3. Лямбда-функция настроена на прослушивание s3:ObjectCreated:* событий из области загрузки
  4. Когда загрузка завершена, функция Lambda запускается событием S3 Message . Частью события является ключ объекта S3
  5. Функция Lambda загружает загруженный файл и пересчитывает sha256
  6. Функция Lambda удаляет файл, если вычисленное значение sha256 отличается от значения sha256, предоставленного клиентом (либо в качестве ключа объекта, либо доступного из метаданных объектов)

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

  1. Сконфигурировать политику сегментов для принимать только те запросы, которые были подписаны
  2. Настройте клиент AWS S3 sdk для использования подписи AWS версии 4, например,

    const s3 = new AWS.S3({apiVersion: '2006-03-01', signatureVersion: 'v4'});
    
  3. Функция S3.putObject () подпишет запрос перед загрузкой файла

S3 не будет хранить объект, если подпись неверна, как описано в AWS CLI S3 FAQ

...