【问题标题】:Put file to Amazon S3 using multipart upload使用分段上传将文件放入 Amazon S3
【发布时间】:2012-01-24 16:02:50
【问题描述】:

我正在尝试通过分段上传使用 Amazon Java SDK 上传文件。这个想法是将上传 ID 传递给小程序,小程序将文件部分放入只读存储桶中。这样一来,我就避免了将 AWS 凭证存储在小程序中。

在我的测试中,我使用 boto (python) 生成了一个上传 ID,并将一个文件存储到存储桶中。效果很好。

我的 Applet 从 S3 收到“403 Access denied”,我不知道为什么。

这是我的代码(部分来自http://docs.amazonwebservices.com/AmazonS3/latest/dev/llJavaUploadFile.html):

AmazonS3 s3Client = new AmazonS3Client();
List<PartETag> partETags = new ArrayList<PartETag>();

long contentLength = file.length();
long partSize = Config.getInstance().getInt("part_size");
String bucketName = Config.getInstance().getString("bucket");
String keyName = "mykey";
String uploadId = getParameter("upload_id");

try {
    long filePosition = 0;
    for (int i = 1; filePosition < contentLength; i++) {

        partSize = Math.min(partSize, (contentLength - filePosition));

        // Create request to upload a part.
        UploadPartRequest uploadRequest = new UploadPartRequest()
            .withBucketName(bucket).withKey(keyName)
            .withUploadId(uploadId).withPartNumber(i)
            .withFileOffset(filePosition)
            .withFile(file)
            .withPartSize(partSize);

        // Upload part and add response to our list.
        partETags.add(s3Client.uploadPart(uploadRequest).getPartETag());

        filePosition += partSize;
    }

    System.out.println("Completing upload");
    CompleteMultipartUploadRequest compRequest = new 
                CompleteMultipartUploadRequest(bucket, 
                                            keyName, 
                                            uploadId, 
                                            partETags);

    s3Client.completeMultipartUpload(compRequest);
} catch (Exception e) {
    s3Client.abortMultipartUpload(new AbortMultipartUploadRequest(
            bucketName, keyName, uploadId));
}

在小程序调试日志中,我找到了这个,然后:

INFO: Sending Request: PUT https://mybucket.s3.amazonaws.com /mykey Parameters: (uploadId: V4hwobOLQ1rYof54zRW0pfk2EfhN7B0fpMJTOpHOcmaUl8k_ejSo_znPI540.lpO.ZO.bGjh.3cx8a12ZMODfA--, partNumber: 1, ) Headers: (Content-Length: 4288546, Content-Type: application/x-www-form-urlencoded; charset=utf-8, ) 
24.01.2012 16:48:42 com.amazonaws.http.AmazonHttpClient handleErrorResponse
INFO: Received error response: Status Code: 403, AWS Service: null, AWS Request ID: DECF32CCFEE9EBF0, AWS Error Code: AccessDenied, AWS Error Message: Access Denied, S3 Extended Request ID: xtL1ixsGM2/vsxJ+cZRHpkPZ23SMfP8hZZjQCQnp8oWGwdS2/aGfYgomihyqaDCQ

你发现代码中有什么明显的错误吗?

谢谢, 斯蒂芬

【问题讨论】:

    标签: java applet amazon-s3


    【解决方案1】:

    虽然您的用例是合理的并且这确实是一个明显的尝试,但我认为Multipart Upload API 的设计并未允许这样做,您实际上违反了安全屏障:

    上传 ID 只是帮助 Multipart Upload API 将各个部分组合在一起的标识符(即更像是一个临时对象密钥),而不是专用的安全机制(见下文)。因此,您仍然需要适当的访问凭证,但由于您正在调用 AmazonS3Client(),它构造了一个新的 Amazon S3 客户端,该客户端将向 Amazon S3 发出匿名请求,因此您的请求会产生 403访问被拒绝

    不幸的是,您可以通过Uploading Objects Using Pre-Signed URLs 实现您想要实现的目标,尽管只是没有多部分功能:

    预签名 URL 可让您访问 URL 中标识的对象, 前提是预签名 URL 的创建者有权 访问该对象。也就是说,如果您收到要上传的预签名 URL 对象,您只能上传对象 预签名 URL 具有上传该对象所需的权限。

    [...] 预签名的 URL 如果您希望您的用户/客户能够上传特定的 object [...],但您不要求它们具有 AWS 安全性 凭据或权限。创建预签名 URL 时,您必须 提供您的安全凭证,指定存储桶名称和对象 密钥、HTTP 方法(上传对象的 PUT)和到期日期 和时间。 [...]

    这段冗长的引述说明了为什么像这样的系统可能需要一个比“仅仅”分发一个上传 ID 更复杂的安全设计(乍一看两者可能很相似)。 p>

    显然,人们希望能够同时使用这两种功能,但这似乎还不可用。

    【讨论】:

    • 非常感谢您的想法。即使如果存储桶是公开可用的,则可以对 S3 执行匿名请求,您的假设似乎是正确的,即不适合我的情况进行分段上传。并且预签名的 URL 不能用于多部分上传,这太糟糕了。但是,我决定使用 AWS IAM 机制为存储桶设置只写策略,并将凭证存储在小程序中相应配置的新用户。从安全角度来看,应该没问题。
    • @schneck:促进 IAM 只写策略确实是一个很好的选择,我过于关注如何你试图实现你的目标而不是实际用例 - 您可以通过 Making Requests Using IAM User Temporary Credentials 更进一步,以完全避免在您的小程序中存储永久凭据。
    • 只写的公共存储桶的危险难道不是有人可以使用 curl 向您的存储桶发送垃圾邮件吗?还是我错过了什么?
    猜你喜欢
    • 1970-01-01
    • 2017-08-23
    • 2014-10-14
    • 2015-06-25
    • 2011-07-21
    • 2015-03-17
    • 2021-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多