17

ファイルを PUT しようとして、一晩中 Amazon S3 の署名付き URL をいじっています。Java コードで署名付き URL を生成します。

    AWSCredentials credentials = new BasicAWSCredentials( accessKey, secretKey );
    client = new AmazonS3Client( credentials );
    GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest( bucketName, "myfilename", HttpMethod.PUT);
    request.setExpiration( new Date( System.currentTimeMillis() + (120 * 60 * 1000) ));
    return client.generatePresignedUrl( request ).toString();

次に、生成された署名済みの URL を使用して、curl を使用してファイルを PUT したいと考えています。

curl -v -H "content-type:image/jpg" -T mypicture.jpg https://mybucket.s3.amazonaws.com/myfilename?Expires=1334126943&AWSAccessKeyId=<accessKey>&Signature=<generatedSignature>

私は、GET のように、これは公開されていないバケットで機能すると想定しました (それが署名済みのポイントですよね?) まあ、試行するたびにアクセスが拒否されました。最後に、フラストレーションから、バケットのアクセス許可を変更して、全員が書き込みできるようにしました。もちろん、署名付き URL は機能しました。バケットから EVERYONE 権限をすぐに削除しました。現在、自分の自己署名付き URL によってバケットにアップロードされたアイテムを削除する権限がありません。アップロードしたものに x-amz-acl ヘッダーを配置する必要があったことがわかりました。それを正しく行う前に、削除できないオブジェクトをさらにいくつか作成すると思います。

これにより、いくつかの疑問が生じます。

  • PUT と生成された署名付き URL を使用して curl でアップロードするにはどうすればよいですか?
  • アップロードしたファイルと、それをテストするために作成したバケットを削除するにはどうすればよいですか?

最終的な目標は、携帯電話がこの署名付き URL を使用して画像を PUT することです。概念実証として、curl で実行しようとしています。

更新: Amazon フォーラムで質問しました。回答が提供されている場合は、ここに回答として掲載します。

4

2 に答える 2

33

これは確かに少し不可解です。AWS SDK for Javaのバグだと思います(以下を参照)。しかし、何よりもまず、次のcurlコマンドはファイルをそのままアップロードします (もちろん、更新済みの署名済み URL を前提としています)。 ):

curl -v -T mypicture.jpg https://mybucket.s3.amazonaws.com/myfilename?Expires=1334126943&AWSAccessKeyId=<accessKey>&Signature=<generatedSignature>

つまり、結果として(または)Content typeを生成するヘッダーを除外しましたが、これは明らかに望ましくありません。したがって、さらなる掘削が命じられました。application/octet-streambinary/octet-stream

背景/分析

Amazon S3への PUT (および DELETE と HEAD) リクエストの事前署名付き URL は、このサイトの関連する質問で少なくとも証明されているわけではなく、原則として機能することが知られています (たとえば、事前署名付きを使用して curl で s3 にアップロードするための私の回答を参照してください)。 URL (取得 403) )。

促進されたQuery String Request Authentication Alternativeは、クエリ文字列リクエスト認証方法を示す次の疑似文法を使用するように文書化されています。

StringToSign = HTTP-VERB + "\n" +
    Content-MD5 + "\n" +
    Content-Type + "\n" +
    Expires + "\n" +
    CanonicalizedAmzHeaders +
    CanonicalizedResource;    

これにはヘッダーが含まれてContent-Typeおり、(既に発見したように) いくつかの文書化されたケースではこれが欠落していました。たとえば、AWS チームが PUT request を使用して GetPreSignedURL に応答し、追加されると事前に署名された URL が機能することを確認してください。

これは、 AWS SDK for .NETを使用して簡単に実現できます。これは、まさにそれを行う便利なメソッドGetPreSignedUrlRequest.WithContentTypeを提供します。

このリクエストの ContentType プロパティを設定します。このプロパティのデフォルトは「binary/octet-stream」ですが、他に何か必要な場合は、このプロパティを設定できます。

したがって、それぞれのサンプルUpload an Object Using Pre-Signed URL - AWS SDK for .NETを次のように拡張すると、期待どおりに (つまり、試みたとおりに) curlを介してアップロードできる、コンテンツ タイプを含む動作する事前署名付き URL が生成されます。

    // ...
    GetPreSignedUrlRequest request = new GetPreSignedUrlRequest();
    // ...
    request.WithContentType("image/jpg");
    // ...

ここで、意味的に同一のサンプルUpload an Object Using Pre-Signed URL - AWS SDK for Javaを同様の方法で拡張したいと考えていますが、(すでにお気づきのとおり)、これを実現するための専用の方法はありません。ただし、これは便利なメソッドが不足している可能性があり、最終的にaddRequestParameter ()またはsetResponseHeaders( ) を介して達成できる可能性があります。

  // ...
  request.setExpiration( new Date( System.currentTimeMillis() + (120 * 60 * 1000) ));
  request.addRequestParameter("content-type", "image/jpg");
  return client.generatePresignedUrl( request ).toString();
  // ...

ただし、両方のメソッドのドキュメントは他の目的を示唆しており、実際には機能しません。つまり、どのコンテンツ タイプがそのように設定されていても (存在する場合)、常に同じ署名を生成します。

SDK をさらにデバッグすると、上記の疑似文法に従ってクエリ文字列認証を計算する意味的に類似したコア メソッドが両方とも提供されていることがわかります。.NET の場合は buildSigningString () 、Java の場合はmakeS3CanonicalString()を参照してください。

しかし、Java バージョンのAdd all Interested Headers to a list, then sort themのそれぞれのコードは、「Interesting」が Content-MD5、Content-Type、Date、および x-amz- として定義されているため、実際には実行されません。これらのヘッダーを何らかの形で提供する方法は実際にはありません。これはクラスDefaultRequestでのみ使用でき、前者を初期化するために使用されるクラスGeneratePresignedUrlRequestでは使用できません。これは、署名を計算するための入力として使用されます。保護されたメソッドcreateRequest()を参照してください。

興味深いことに、.NET と Java でクエリ文字列認証を計算する 2 つの方法は、コール スタック上のヘッダーソースとパラメーターソースのほぼ逆の組み合わせから入力を構成します。これは、Java バグの原因を示唆している可能性がありますが、明らかに、それは解読するのが難しいだけかもしれません。つまり、内部アーキテクチャはもちろん大幅に異なる可能性があります。

暫定的な結論

これには 2 つの角度があります。

  • AWS SDK for Java には、コンテンツ タイプを設定するための便利な方法が明らかに欠けています。これは比較的まれかもしれませんが、それに応じて他の AWS SDK で説明されている明らかなユース ケースです。AWS 関連のバックエンド サービスで広く使用されていることを考えると、これは驚くべきことです。 .
  • とにかく、たとえば.NETバージョンと比較して、クエリ文字列リクエスト認証の実装方法に何か怪しいものがあるようです-これもまた、コア機能であることを考えると驚くべきことですが、これはまだS3モデル内にあります/名前空間であるため、上記のそれぞれの使用例でのみ必要になる場合があります。

結論として、これを解決する唯一の合理的な方法は更新された SDK であるため、バグ レポートが必要です。明らかに、SDK 機能を複製/拡張して、この特殊なケースを個別に説明することもできます (理想的には、送信できる方法で)。aws-sdk-for-java プロジェクトのプル リクエスト) が、互換性があり保守可能な方法でこれを適切に行うのは少し難しいように思われるため、SDK メンテナー自身が行うのが最善の方法である可能性があります。

于 2012-04-22T16:47:25.917 に答える
0

この問題にも遭遇しました。バックエンドでファイルがアップロードされた時点を既に追跡しているため、クライアントが Rails アプリを使用して copy_from を呼び出してファイルをアップロードした後に、コンテンツ タイプを設定するという回避策がありました。

于 2012-09-25T21:40:39.470 に答える