48 votes

Question sur l'architecture et la conception concernant le téléchargement de photos à partir de l'application iPhone et de S3

Je veux permettre aux utilisateurs d'une application iPhone de télécharger des photos et d'utiliser Amazon S3. Il y a deux façons de procéder selon moi :

  1. Téléchargement de l'iPhone vers mon serveur, qui le transmet ensuite par proxy à Amazon S3.
  2. Télécharger de l'iPhone directement sur S3

Pour l'option 1, la sécurité est simple. Je n'ai jamais à révéler mon secret S3 à l'iPhone. L'inconvénient, c'est que tout passe par notre serveur pour les téléchargements, ce qui va à l'encontre du but recherché par S3.

Pour l'option 2, c'est théoriquement mieux, mais le problème est le suivant : comment permettre à l'iPhone (ou à toute application mobile sur une plateforme différente) d'écrire dans mon seau S3 sans lui donner mon secret ? En outre, je ne suis pas sûr que ce soit une bonne conception ou non, car le flux serait le suivant : l'iPhone télécharge vers S3, obtient l'URL, puis indique au serveur quelle est l'URL afin qu'il puisse l'ajouter à notre base de données pour la référencer à l'avenir. Cependant, puisque la communication est séparée en deux parties (iphone->S3 vs iPhone->Mon-Serveur), elle est fragile en tant qu'opération non atomique.

J'ai trouvé des informations plus anciennes qui font référence à l'utilisation de Téléchargements par navigateur à l'aide de POST mais je ne suis pas sûr que ce soit toujours l'approche recommandée. J'espère une meilleure solution qui nous permettrait d'utiliser les API REST plutôt que de dépendre de POST. J'ai également vu le SDK bêta pour AWS iOS mais leur documentation ne m'a pas beaucoup aidé et j'ai trouvé une Article Amazon qui n'était pas non plus utile car il vous mettait en garde sur ce que no à faire, mais ne vous indique pas d'approche alternative :

Les SDK mobiles AWS signent l'API envoyées à Amazon Web Services (AWS) afin de valider l'identité l'identité du compte AWS à l'origine de la demande. Sinon, un développeur malveillant malveillant pourrait facilement faire des demandes à l'infrastructure d'un autre développeur. Les demandes sont signées à l'aide d'un AWS Access Key ID et une clé d'accès secrète qu'AWS fournit. La clé d'accès secrète est similaire à un mot de passe, et elle et il est extrêmement important de la garder secrète.

Conseil : vous pouvez afficher tous vos identifiants de sécurité AWS y compris l'ID de la clé d'accès ID de clé d'accès et la clé d'accès secrète, sur le site Web d'AWS à l'adresse http://aws.amazon.com/security-credentials .

Intégrer les informations d'identification dans le code source est problématique pour les logiciels, y compris applications mobiles, car les utilisateurs malveillants malveillants peuvent décompiler le logiciel ou consulter le code source pour récupérer la clé d'accès secrète.

Quelqu'un a-t-il des conseils sur la meilleure conception architecturale et le meilleur flux pour cela ?

Mise à jour : Plus je creuse la question, plus il semble qu'un grand nombre de personnes recommandent d'utiliser la méthode HTTP POST avec le fichier de politique json comme décrit ici : http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/index.html?UsingHTTPPOST.html .

Avec cela, le flux serait quelque chose comme (1) l'iPhone fait une requête à mon serveur, demandant le fichier de politique (2) le serveur génère le fichier de politique json et le rend au client (3) l'iPhone fait HTTP POST de la photo + politique json à S3. Je déteste utiliser HTTP POST d'une manière apparemment maladroite, mais il semble que ce soit mieux parce que mon serveur n'a plus besoin de stocker la photo.

10voto

Adrian Petrescu Points 4618

J'ai discuté de cette question sur les forums AWS avant. Comme je l'ai dit, la bonne solution pour accéder à AWS à partir d'un appareil mobile est d'utiliser l'outil de gestion de l'accès. Gestion des identités et des accès AWS pour générer des clés d'accès temporaires, à privilèges limités, pour chaque utilisateur. Ce service est excellent, mais il est encore en version bêta pour le moment et ne fait pas encore partie du SDK mobile. J'ai le sentiment qu'une fois que ce service sera publié pour de bon, vous le verrez apparaître dans le SDK mobile immédiatement après.

En attendant, générer des URL présignés pour vos utilisateurs, ou par l'intermédiaire de votre propre serveur comme d'autres l'ont suggéré. L'URL présignée permettra à vos utilisateurs d'accéder temporairement par GET ou PUT à un objet S3 dans l'un de vos buckets sans avoir vos informations d'identification (elles sont hachées dans la signature). Vous pouvez lire les détails aquí .

EDITAR : J'ai mis en place une solution correcte pour ce problème, en utilisant la version bêta de IAM. C'est disponible sur sur GitHub, et vous pouvez lire à ce sujet ici .

5voto

shadowmatter Points 502

Vous pouvez télécharger directement de votre iPhone vers S3 à l'aide de l'API REST, et faire en sorte que le serveur soit responsable de la génération de la partie de l'identifiant de l Authorization qui requiert la clé secrète. De cette façon, vous ne risquez pas d'exposer la clé d'accès à quiconque possède un iPhone jailbreaké, tout en évitant de faire peser sur le serveur la charge du téléchargement du fichier. Les détails exacts de la requête à effectuer se trouvent à l'adresse suivante "Exemple d'objet PUT" de "Signer et authentifier les requêtes REST". . I recommande vivement de lire ce document avant de poursuivre.

Le code suivant, écrit en Python, génère la partie de l'interface utilisateur de l'appareil. Authorization qui est dérivée de votre clé d'accès secrète S3. Vous devez substituer votre propre clé d'accès secrète et nom du godet sous forme d'hôte virtuel para _S3_SECRET y _S3_BUCKET_NAME ci-dessous, respectivement :

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)

Appeler ceci avec le nom de fichier foo.txt et content-type text/plain rendements :

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

Notez que si vous exécutez ce code, l'heure renvoyée sera différente, et donc le condensé HMAC codé sera différent.

Le client iPhone n'a plus qu'à envoyer une requête PUT à S3 en utilisant la date retournée et le condensé HMAC. En supposant que

  • le serveur renvoie date_string y auth_string ci-dessus dans un objet JSON nommé serverJson
  • votre clé d'accès S3 (pas votre secret, qui est seulement sur le serveur) est nommée kS3AccessKey
  • votre nom de seau S3 (défini à my-bucket-name ci-dessus) est nommé kS3BucketName
  • le contenu du fichier est mis en forme dans un fichier NSData objet nommé data
  • le nom de fichier qui a été envoyé au serveur est une chaîne nommée filename
  • le type de contenu qui a été envoyé au serveur est une chaîne nommée contentType

Vous pouvez ensuite procéder comme suit pour créer le 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]];

Ensuite, vous pouvez émettre la demande. Si vous utilisez l'excellent Bibliothèque AFNetworking alors vous pouvez envelopper request dans un AFXMLRequestOperation en utilisant XMLDocumentRequestOperationWithRequest:success:failure: puis en invoquant son start méthode. N'oubliez pas de libérer headers y request une fois terminé.

Notez que le client a obtenu la valeur de l'élément Date du serveur. Cela est dû au fait que, comme Amazon le décrit sous "Exigence de l'horodateur" :

" Un horodatage valide (utilisant soit l'en-tête HTTP Date, soit une alternative x-amz-date) est obligatoire pour les demandes authentifiées. En outre, l'horodatage du client inclus dans une demande authentifiée doit être dans les 15 minutes de l'heure du système Amazon S3 lorsque la demande est reçue. Si ce n'est pas le cas, la demande échouera avec le code d'état d'erreur RequestTimeTooSkewed. "

Ainsi, au lieu de compter sur le fait que le client dispose de l'heure exacte pour que la requête aboutisse, il faut compter sur le serveur, qui devrait utiliser NTP (et un démon tel que ntpd ).

4voto

hipplar Points 3185

Téléchargez sur votre serveur, puis postez sur S3. Du point de vue de l'architecture, il est préférable d'effectuer cette opération depuis votre serveur. De plus, si vous souhaitez stocker des données sur l'image que vous envoyez à S3, vous aurez probablement besoin d'un appel côté serveur.

De plus, votre clé d'accès secrète est stockée dans un environnement plus sécurisé. Le vôtre.

Si vous êtes préoccupé par l'évolutivité et que vous êtes amené à effectuer un nombre considérable de transferts S3, j'envisagerais d'héberger votre serveur sur une instance EC2. Le transfert de données entre les deux est gratuit (à condition que vous stockiez vos données dans les centres de données suivants).

Il n'y a pas de frais de transfert de données pour les données transférées entre Amazon EC2 et Amazon S3 dans la même région ou pour les données transférées entre la région Amazon EC2 Northern Virginia et la région Amazon S3 US Standard." Amazon Simple Storage Service (Amazon S3)

Il y a beaucoup de messages ici sur SO Amazon - Coût de l'EC2 ? (exemple) sur les avantages et les inconvénients de l'utilisation d'EC2.

0voto

Dat Nguyen Points 54

Je suis confus. Pourquoi amazon a créé le sdk ios pour télécharger des données sur le s3 puis nous dit de ne pas l'utiliser ( L'intégration des informations d'identification dans le code source est problématique pour les logiciels, y compris les applications mobiles, car les utilisateurs malveillants peuvent décompiler le logiciel ou visualiser le code source pour récupérer la clé d'accès secrète. ) ???

0voto

Syed Absar Points 1019

Ils ont peut-être fourni le sdk dans le but que l'application puisse permettre l'authentification à des comptes s3 individuels ? par exemple une application qui permet aux utilisateurs de stocker des fichiers dans leur propre seau (celui de l'utilisateur) au lieu de celui du fournisseur ? je pense qu'il y a une faille de sécurité à fusionner les clés avec l'application et à la distribuer. n'importe qui peut les (mal)utiliser une fois que les clés sont révélées de toute façon (ce n'est jamais sûr quand vous les donnez). d'un autre côté, garder la fonctionnalité réservée au serveur gardera vos clés transparentes pour l'utilisateur, n'est-ce pas ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X