Архитектурно-дизайнерский вопрос о загрузке фотографий из приложения iPhone и S3 - PullRequest
48 голосов
/ 19 декабря 2010

Я хочу разрешить пользователям приложения для iPhone загружать фотографии и использовать Amazon S3. Есть два способа, которые я вижу:

  1. Загрузка с iPhone на мой сервер, который затем передает его на Amazon S3.
  2. Загрузка с iPhone напрямую на S3

Для варианта 1 безопасность проста. Мне никогда не придется рассказывать iPhone мой секрет S3. Недостатком является то, что все передается через наш сервер для загрузки, что побеждает цель перехода на S3.

Для варианта 2 теоретически это лучше, но вопрос в том, как вы позволяете iPhone (или любому мобильному приложению на другой платформе) записывать в мое ведро S3, не раскрывая ему своего секрета? Кроме того, я не уверен, является ли это хорошим дизайном или нет, потому что поток будет таким: iphone загружает на S3, получает URL, а затем сообщает серверу, что такое URL, чтобы он мог добавить его в нашу базу данных для ссылки в будущее. Однако, поскольку связь разделена на две части (iphone-> S3 против iPhone-> My-Server), она становится хрупкой как неатомарная операция.

Я нашел более старую информацию, которая ссылается на Загрузка через браузер с использованием POST , но не уверен, что это все еще рекомендуемый подход. Я надеюсь на лучшее решение, где мы можем просто использовать REST API, а не полагаться на POST. Я также видел AWS iOS Beta SDK , но их документы не сильно помогли, и я нашел статью Amazon , которая была столь же бесполезной, поскольку она предупреждает вас о том, что не сделать, но не говорит вам альтернативный подход:

Мобильные SDK AWS подписывают API запросы, отправленные на веб-сервисы Amazon (AWS) для подтверждения личность аккаунта AWS, делающего запрос. В противном случае, злой разработчик может легко делать запросы в инфраструктуру другого разработчика. Запросы подписываются с использованием AWS Идентификатор ключа доступа и секретный ключ доступа что предоставляет AWS. Секретный доступ Ключ похож на пароль, и это крайне важно хранить в тайне.

Совет. Вы можете просмотреть все свои AWS. учетные данные безопасности, включая Access Идентификатор ключа и секретный ключ доступа, на Веб-сайт AWS по адресу http://aws.amazon.com/security-credentials.

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

Есть ли у кого-нибудь совет по поводу лучшего архитектурного дизайна и потока для этого?

Обновление: Чем больше я копаюсь в этом, кажется, что многие люди рекомендуют использовать метод HTTP POST с файлом политики json, как описано здесь: http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/index.html?UsingHTTPPOST.html.

При этом поток будет примерно таким: (1) iPhone отправляет запрос на мой сервер, запрашивая файл политики (2) сервер генерирует файл политики json и возвращает клиенту (3) iPhone выполняет HTTP POST для фото + json политика к S3. Я ненавижу то, что я использую HTTP POST явно грязным способом, но, кажется, это лучше, потому что это избавляет мой сервер от необходимости хранить фотографию.

Ответы [ 5 ]

10 голосов
/ 21 декабря 2010

Я обсуждал эту проблему на форумах AWS ранее.Как я уже сказал, правильное решение для доступа к AWS с мобильного устройства заключается в использовании службы AWS Identity and Access Management для создания временных ключей доступа с ограниченными правами для каждого пользователя.Сервис отличный, но пока он находится в бета-версии и пока не входит в состав мобильного SDK.У меня такое чувство, как только эта вещь будет выпущена навсегда, вы сразу же увидите ее в мобильном SDK.

До этого времени генерирует предварительно назначенные URL-адреса для ваших пользователей или через проксиваш собственный сервер, как некоторые другие предложили.Предопределенный URL-адрес позволит вашим пользователям временно получить или положить объект S3 в одном из ваших сегментов без фактического наличия ваших учетных данных (они хэшируются в подписи).Вы можете прочитать подробности здесь .

EDIT : я реализовал правильное решение этой проблемы, используя предварительную бета-версию IAM.Он доступен на GitHub, и вы можете прочитать об этом здесь .

5 голосов
/ 06 февраля 2013

Вы можете загружать данные прямо с вашего iPhone на S3, используя REST API, и при этом сервер отвечает за генерацию части значения заголовка Authorization, для которой требуется секретный ключ. Таким образом, вы не рискуете раскрыть ключ доступа кому-либо с взломанным iPhone, в то время как вы не несете бремени загрузки файла на сервер. Точные детали запроса на отправку можно найти в разделе «Пример объекта PUT» в разделе «Подписание и аутентификация запросов REST» . Я настоятельно рекомендую прочитать этот документ, прежде чем продолжить.

Следующий код, написанный на Python, генерирует часть значения заголовка Authorization, полученную из вашего секретного ключа доступа S3. Вам следует заменить свой собственный секретный ключ доступа и имя корзины в форме виртуального хоста для _S3_SECRET и _S3_BUCKET_NAME ниже, соответственно:

import base64
from datetime import datetime
import hmac
import sha

# Replace these values.
_S3_SECRET = "my-s3-secret"
_S3_BUCKET_NAME = "my-bucket-name"

def get_upload_header_values(content_type, filename): 
  now = datetime.utcnow()
  date_string = now.strftime("%a, %d %b %Y %H:%M:%S +0000")
  full_pathname = '/%s/%s' % (_S3_BUCKET_NAME, filename)
  string_to_sign = "PUT\n\n%s\n%s\n%s" % (
      content_type, date_string, full_pathname)
  h = hmac.new(_S3_SECRET, string_to_sign, sha)
  auth_string = base64.encodestring(h.digest()).strip()
  return (date_string, auth_string)

Вызов этого с именем файла foo.txt и типом содержимого text/plain дает:

>>> get_upload_header_values('text/plain', 'foo.txt')
('Wed, 06 Feb 2013 00:57:45 +0000', 'EUSj3g70aEsEqSyPT/GojZmY8eI=')

Обратите внимание, что если вы запустите этот код, возвращаемое время будет другим, и поэтому закодированный дайджест HMAC будет другим.

Теперь клиент iPhone просто должен отправить запрос PUT на S3, используя возвращенную дату и дайджест HMAC. Предполагая, что

  • сервер возвращает date_string и auth_string выше в некотором объекте JSON с именем serverJson
  • ваш ключ доступа S3 (не ваш секрет, который есть только на сервере) называется kS3AccessKey
  • имя вашей корзины S3 (установлено на my-bucket-name выше) с именем kS3BucketName
  • содержимое файла маршалируется в NSData объект с именем data
  • имя файла, которое было отправлено на сервер, является строкой с именем filename
  • тип содержимого, отправленный на сервер, представляет собой строку с именем contentType

Затем вы можете сделать следующее для создания NSURLRequest:

NSString *serverDate = [serverJson objectForKey:@"date"]
NSString *serverHmacDigest = [serverJson objectForKey:@"hmacDigest"]

// Create the headers.
NSMutableDictionary *headers = [[NSMutableDictionary alloc] init];
[headers setObject:contentType forKey:@"Content-Type"];
NSString *host = [NSString stringWithFormat:@"%@.s3.amazonaws.com", kS3BucketName]
[headers setObject:host forKey:@"Host"];
[headers setObject:serverDate forKey:@"Date"];
NSString *authorization = [NSString stringWithFormat:@"AWS %@:%@", kS3AccessKey, serverHmacDigest];
[headers setObject:authorization forKey:@"Authorization"];

// Create the request.
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:data];
[request setHTTPMethod:@"PUT"];
NSString *postUrl = [NSString stringWithFormat:@"http://%@.s3.amazonaws.com/%@", kS3BucketName, filename];
[request setURL:[NSURL URLWithString:postUrl]];

Далее вы можете оформить запрос. Если вы используете превосходную библиотеку AFNetworking , то вы можете обернуть request в AFXMLRequestOperation объект, используя XMLDocumentRequestOperationWithRequest:success:failure:, а затем вызвать его start метод. Не забудьте отпустить headers и request, когда закончите.

Обратите внимание, что клиент получил значение заголовка Date с сервера. Это связано с тем, что Amazon описывает в разделе «Требование к отметке времени» :

"Действительная метка времени (с использованием заголовка HTTP-даты или альтернативы x-amz-date) обязательна для аутентифицированных запросов. Кроме того, метка времени клиента, включенная в аутентифицированный запрос, должна находиться в пределах 15 минут от Amazon S3 системное время, когда запрос получен. Если нет, запрос завершится ошибкой с кодом состояния ошибки RequestTimeTooSkewed. "

Таким образом, вместо того, чтобы полагаться на правильное время клиента для успешного выполнения запроса, положитесь на сервер, который должен использовать NTP (и демон типа ntpd).

4 голосов
/ 20 декабря 2010

Загрузите на свой сервер, а затем отправьте на S3. С точки зрения архитектуры вы захотите сделать это со своего сервера. Есть много вещей, которые могут пойти не так во время передачи данных, вы можете лучше обрабатывать их на сервере, и если вы хотите сохранить какие-либо данные об изображении, которое вы отправляете на S3, вам, вероятно, все равно придется обратиться к серверу.

Кроме того, ваш секретный ключ доступа хранится в более безопасной среде. Ваш собственный.

Если вы беспокоитесь о масштабируемости и собираетесь выполнять значительное количество передач S3, я бы рассмотрел возможность размещения вашего сервера и экземпляра EC2. Передача данных между ними бесплатна (если вы храните данные в следующих дата-центрах).

Плата за передачу данных не взимается за данные, передаваемые между Amazon EC2 и Amazon S3 в пределах одного региона, или за данные, передаваемые между регионом Amazon EC2 Северная Вирджиния и стандартным регионом Amazon S3 US. Amazon S3)

Здесь много сообщений о SO Amazon - стоимость EC2? (пример) о плюсах и минусах использования EC2.

0 голосов
/ 27 декабря 2010

они могли предоставить sdk для того, чтобы приложение могло разрешить аутентификацию отдельным учетным записям s3?Например, приложение, которое позволяет пользователям хранить файлы в своем (пользовательском) хранилище вместо провайдера?я чувствую недостаток безопасности в слиянии ключей с приложением и его распространении.любой может (не) использовать их, как только ключи будут раскрыты (это никогда не безопасно, когда вы их раздаете).с другой стороны, сохранение функции, зарезервированной для сервера, сделает ваши ключи прозрачными для пользователя, не так ли?

0 голосов
/ 21 декабря 2010

Я в замешательстве.Почему amazon приходит с ios sdk для загрузки данных в s3, а затем говорит нам не использовать его ( Встраивание учетных данных в исходный код проблематично для программного обеспечения, включая мобильные приложения, поскольку злонамеренные пользователи могут декомпилировать программное обеспечение илипросмотреть исходный код для получения секретного ключа доступа ) ???

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