Як зберігати дані в S3 та дозволити користувачеві безпечний доступ з рельєфним API / iOS клієнтом?


93

Я новачок у написанні Rails та API. Мені потрібна допомога з рішенням для зберігання S3. Ось моя проблема.

Я пишу API для програми для iOS, де користувачі входять із API Facebook на iOS. Сервер перевіряє прав користувача щодо видачі маркера Facebook користувачеві iOS та видає тимчасовий маркер сеансу. З цього моменту користувачеві потрібно завантажити вміст, який зберігається в S3. Цей вміст належить лише користувачеві та підмножині його друзів. Цей користувач може додати більше вмісту до S3, до якого може отримати доступ та сама група людей. Я думаю, це схоже на приєднання файлу до групи у Facebook ...

Є два способи взаємодії користувача з S3 ... залишити його на сервері або змусити сервер видати тимчасовий маркер S3 (не впевнений у можливостях тут), і користувач може потрапити на URL-адреси вмісту безпосередньо до S3. Я виявив, що це питання говорить про підходи, однак воно справді датується (2 роки тому): Архітектурне та дизайнерське питання щодо завантаження фотографій із програми iPhone та S3

Отже, питання:

  • Чи є спосіб обмежити користувача доступу до лише деякого вмісту на S3, коли видається тимчасовий маркер? Як я можу це зробити? Припустимо, що ... скажімо, 100 000 або більше користувачів.
  • Це гарна ідея дозволити пристрою iOS безпосередньо витягувати цей вміст?
  • Або повинен дозволити серверу контролювати весь вміст, що передається (це вирішує безпеку, звичайно)? Чи означає це, що я маю завантажити весь вміст на сервер, перш ніж передавати його підключеним користувачам?
  • Якщо ви знаєте рейки ... чи можу я скористатися скріпкою та дорогоцінними каменями aws-sdk для досягнення такої якості?

Вибачте за багато питань, і я вдячний за будь-яке розуміння проблеми. Дякую :)


1
знайшов це і подумав, що я прокоментую інших, хто шукає docs.aws.amazon.com/AmazonS3/latest/dev/…
dibble

Відповіді:


113

Використовуючи самоцвіт aws-sdk , ви можете отримати тимчасову підписану URL-адресу для будь-якого об’єкта S3, зателефонувавши url_for:

s3 = AWS::S3.new(
  :access_key_id => 1234,
  :secret_access_key => abcd
)
object = s3.buckets['bucket'].objects['path/to/object']
object.url_for(:get, { :expires => 20.minutes.from_now, :secure => true }).to_s

Це дасть вам підписану URL-адресу тимчасового використання лише для цього об’єкта в S3. Термін дії закінчується через 20 хвилин (у цьому прикладі), і це корисно лише для одного об’єкта.

Якщо у вас багато об’єктів, необхідних клієнту, вам потрібно буде видати багато підписаних URL-адрес.

Або повинен дозволити серверу контролювати весь вміст, що передається (це вирішує безпеку, звичайно)? Чи означає це, що я маю завантажити весь вміст на сервер, перш ніж передавати його підключеним користувачам?

Зауважте, що це не означає, що серверу потрібно завантажувати кожен об’єкт, йому потрібно лише автентифікувати та авторизувати певних клієнтів для доступу до певних об’єктів у S3.

Документи API від Amazon: https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth


3
Дякую за це @ejdyksen. Я розробив саме таке рішення (саме я не оновив запитання своєю відповіддю)! Тож моїм рішенням було зробити автентифіковані URL-адреси для GET-запитів. Однак, коли користувач вносить вміст, він створює ресурси для певного / bucket / user / objectname розташування, використовуючи федеральний маркер IAM (тимчасові облікові дані, які закінчуються) із доданою політикою для дозволу доступу / bucket / user / *. тому жоден користувач у системі не може завдати шкоди вмісту інших користувачів. Здається, працює нормально. Вдячний за вашу відповідь.
1212 року

5
Якщо ви використовуєте v2 Aws-sdk-ruby, зауважте, що методи дещо інші: docs.aws.amazon.com/sdkforruby/api/Aws/S3/…
vijucat

2
Чи не є ризиком, що користувач може побачити мій ключ доступу? Є також секретний ключ (перетворений)
user2503775

3
@ Деніс вся справа в тому, що файл не повинен потрапляти на ваш сервер. Посилання не містить ваших облікових даних AWS. Він може містити ACCESS_KEY_ID(я не пам'ятаю вгорі голови), але це не є секретом.
ejdyksen

2
@ejdyksen ви праві, я просто перевірив, що URL-адреса містить лише те AWS_ACCESS_KEY_ID. Спочатку я думав, що AWS_SECRET_ACCESS_KEYце також відображається, але це не так.
Денніс

46

Вищевказані відповіді використовують стару дорогу aws-sdk-v1, а не нову версію aws-sdk-ресурсів 2.

Новий спосіб:

aws_resource = Aws::S3::Resource::new
aws_resource.bucket('your_bucket').object('your_object_key').presigned_url(:get, expires_in: 1*20.minutes)

де your_object_key - шлях до вашого файлу. Якщо вам потрібно це знайти, ви б використали щось на зразок:

s3 = Aws::S3::Client::new
keys = []
s3.list_objects(bucket: 'your_bucket', prefix: 'your_path').contents.each { |e| 
  keys << e.key
}

Цю інформацію було приголомшливо важко розкопати, і я майже просто здався і скористався старшим коштовним каменем.

Довідково

http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#presigned_url-instance_method


1
expires_inочікує, що дані у формі секунд, просто переконайтеся, що перетворити їх першими.
frillybob

"ArgumentError (очікується: термін дії закінчується через кілька секунд)"
rewwolf
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.