web-dev-qa-db-ja.com

iPhoneアプリとS3からの写真のアップロードに関するアーキテクチャとデザインの質問

IPhoneアプリのユーザーが写真をアップロードしてAmazonS3を使用できるようにしたい。私がこれについて行くのを見る2つの方法があります:

  1. IPhoneからサーバーにアップロードします。サーバーはそれをAmazonS3にプロキシします。
  2. IPhoneからS3に直接アップロードする

オプション1の場合、セキュリティは簡単です。 iPhoneにS3の秘密を教える必要はありません。欠点は、アップロードのためにすべてがサーバーを介してプロキシされるため、S3に移動する目的が損なわれることです。

オプション2の場合、理論的にはより良いですが、問題は、iPhone(または別のプラットフォーム上のモバイルアプリ)が秘密を明かさずにS3バケットに書き込むことができるようにする方法です。さらに、フローが次のようになるため、これが適切な設計であるかどうかはわかりません。iphoneはS3にアップロードし、URLを取得してから、サーバーにURLを通知して、データベースで参照できるようにします。未来。ただし、通信は2つのレッグ(iphone-> S3とiPhone-> My-Server)に分かれているため、非アトミック操作として脆弱なままになります。

POSTを使用したブラウザベースのアップロード を使用して参照する古い情報をいくつか見つけましたが、それがまだ推奨されるアプローチであるかどうかはわかりません。 POSTに依存するのではなく、RESTAPIを使用できるより良いソリューションを望んでいます。 AWS iOS Beta SDK も見ましたが、ドキュメントはあまり役に立ちませんでした。 Amazonの記事 は、何について警告するので、同様に役に立たなかったことがわかりました実行しないが、代替アプローチを教えてくれません:

モバイルAWSSDKは、リクエストを行っているAWSアカウントのIDを検証するために、Amazon Web Services(AWS)に送信されたAPIリクエストに署名します。そうしないと、悪意のある開発者が別の開発者のインフラストラクチャに簡単にリクエストを送信する可能性があります。リクエストは、AWSが提供するAWSアクセスキーIDとシークレットアクセスキーを使用して署名されます。シークレットアクセスキーはパスワードに似ており、秘密にしておくことが非常に重要です。

ヒント:アクセスキーIDとシークレットアクセスキーを含むすべてのAWSセキュリティ認証情報は、AWS Webサイト( http://aws.Amazon.com/security-credentials )で表示できます。

悪意のあるユーザーがソフトウェアを逆コンパイルしたり、ソースコードを表示してシークレットアクセスキーを取得したりする可能性があるため、ソースコードに資格情報を埋め込むことは、モバイルアプリケーションを含むソフトウェアにとって問題があります。

誰かがこれのための最高の建築設計と流れについて何かアドバイスがありますか?

更新:これを深く掘り下げるほど、多くの人々がjsonポリシーでHTTP POSTメソッドを使用することを推奨しているようですここで説明されているファイル: http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/index.html?UsingHTTPPOST.html

これにより、フローは次のようになります(1)iPhoneがサーバーにリクエストを送信し、ポリシーファイルを要求します(2)サーバーがjsonポリシーファイルを生成してクライアントに返します(3)iPhoneがHTTP POSTを実行します写真+ S3へのjsonポリシー。 HTTP POSTを明らかに厄介な方法で使用しているのは嫌いですが、サーバーが写真を保存する必要がまったくないため、より良いように見えます。

48
TMC

この問題については前に説明しました AWSフォーラムで 。私がそこで言っているように、モバイルデバイスからAWSにアクセスするための適切なソリューションは、 AWS Identity and Access Management サービスを使用して、各ユーザーの一時的な制限付き特権アクセスキーを生成することです。このサービスは素晴らしいですが、現時点ではまだベータ版であり、モバイルSDKの一部ではありません。これが完全にリリースされたら、すぐにモバイルSDKで確認できると思います。

それまでは、 事前に署名されたURLを生成する ユーザー用に、または他の人が提案しているように独自のサーバーを介してプロキシします。事前に署名されたURLを使用すると、ユーザーは実際に認証情報を持っていなくても、バケットの1つにあるS3オブジェクトに一時的にGETまたはPUTできます(署名にハッシュされます)。あなたは詳細について読むことができます ここ

[〜#〜] edit [〜#〜]:IAMのプレビューベータを使用して、この問題の適切なソリューションを実装しました。それはGitHubで 利用可能 です、そしてあなたは ここでそれについて読む です。

10
Adrian Petrescu

REST APIを使用して、iPhoneからS3に直接アップロードし、秘密鍵を必要とするAuthorizationヘッダー値の一部をサーバーに生成させることができます。これジェイルブレイクされたiPhoneを持っている人にアクセスキーを公開するリスクはありませんが、サーバーにファイルをアップロードする負担はありません。リクエストの正確な詳細は、 ()にあります。 「SigningandAuthenticating REST Requests」 の「ExampleObjectPUT」。私はそのドキュメントを読むことを強くお勧めします先に進む前に。

Pythonで記述された次のコードは、S3シークレットアクセスキーから派生したAuthorizationヘッダー値の一部を生成します。以下の_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クライアントは、返された日付とHMACダイジェストを使用してS3にPUTリクエストを発行する必要があります。仮定して

  • サーバーは、上記のdate_stringauth_stringserverJsonという名前のJSONオブジェクトで返します。
  • 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ライブラリ を使用している場合は、 XMLDocumentRequestOperationWithRequest:success:failure: 、を使用してrequestAFXMLRequestOperationオブジェクトにラップできます。次に、そのstartメソッドを呼び出します。完了したら、headersrequestを解放することを忘れないでください。

クライアントがサーバーからDateヘッダーの値を取得したことに注意してください。これは、Amazonが "タイムスタンプ要件" で説明しているように、次の理由によるものです。

「認証されたリクエストには、有効なタイムスタンプ(HTTP Dateヘッダーまたはx-amz-dateの代替を使用)が必須です。さらに、認証されたリクエストに含まれるクライアントのタイムスタンプは、AmazonS3システム時刻から15分以内である必要があります。リクエストを受信したとき。そうでない場合、リクエストはRequestTimeTooSkewedエラーステータスコードで失敗します。」

したがって、要求が成功するために正しい時刻を持つクライアントに依存する代わりに、サーバーに依存します。サーバーはNTP(およびntpdのようなデーモン)を使用する必要があります) 。

5
shadowmatter

サーバーにアップロードしてから、S3に投稿します。アーキテクチャの観点からは、サーバーからこれを実行する必要があります。データ転送中に問題が発生する可能性のあるものはたくさんあり、サーバー上でより適切に処理できます。S3に送信する画像に関するデータを保存する場合は、とにかくサーバー側に電話をかけることになります。

さらに、シークレットアクセスキーはより安全な環境に保存されます。あなた自身の。

スケーラビリティが心配で、かなりの数のS3転送を実行する場合は、サーバーをEC2インスタンスでホストすることを検討します。 2つの間でのデータの転送は無料です(次のデータセンターにデータを保存している場合)。

同じリージョン内のAmazonEC2とAmazonS3の間で転送されるデータ、またはAmazonEC2北バージニアリージョンとAmazonS3US標準リージョンの間で転送されるデータにはデータ転送料金はかかりません。 " Amazon Simple Storage Service(Amazon S3 )

EC2を使用することの長所と短所についてSO Amazon --EC2コスト? (例))に多くの投稿があります。

4
Larry Hipp

よくわかりません。 Amazonがiossdkを使用してデータをs3にアップロードし、それを使用しないように指示するのはなぜですか(ソースコードに資格情報を埋め込むことは、悪意のあるユーザーがソフトウェアを逆コンパイルできるため、モバイルアプリケーションを含むソフトウェアにとって問題があります)または、ソースコードを表示してシークレットアクセスキーを取得します)???

0
Dat Nguyen

アプリケーションが個々のs3アカウントへの認証を許可できるという目的で、SDKを提供した可能性がありますか?たとえば、ユーザーがプロバイダーではなく独自の(ユーザーの)バケットにファイルを保存できるアプリですか?キーをアプリケーションとマージして配布する際にセキュリティ上の欠陥を感じます。とにかくキーが明らかになると、誰でもそれらを(誤)使用することができます(あなたがそれを配っているとき、それは決して安全ではありません)。一方、機能をサーバーに予約しておくと、キーがユーザーに対して透過的になりますね。

0
Syed Absar