从S3获取预签名URL,即使输入了错误的访问密钥或秘密密钥。

huangapple go评论69阅读模式
英文:

Getting preSignedUrl from s3 even if wrong access key or secret key is entered

问题

我正在生成一个预签名URL,然后通过该URL上传文件。
问题是,即使我输入错误的访问密钥或秘密密钥,我也会获得预签名URL,但如果我尝试使用该URL上传,则会收到400错误。

<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>AuthorizationQueryParametersError</Code>
    <Message>Query-string authentication version 4 requires the X-Amz-Algorithm, X-Amz-Credential, X-Amz-Signature, X-Amz-Date, X-Amz-SignedHeaders, and X-Amz-Expires parameters.</Message>
    <RequestId>{requestId}</RequestId>
    <HostId>{hostId}</HostId>
</Error>

有没有一种方法可以在生成预签名URL时获得错误,这样我就不必尝试上传文件了。

AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("accessKey", "secretKey")))
                .withRegion(clientRegion)
                .build();

GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, objectKey)
 .withMethod(HttpMethod.PUT)
 .withExpiration(expiration);

URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
英文:

I am generating a preSignedUrl and then uploading the file through that url.
The issue is that even if I enter the wrong access key or secret key I get the preSignedUrl, though if I try to upload using that url I get 400 error.

  &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
    &lt;Error&gt;
        &lt;Code&gt;AuthorizationQueryParametersError&lt;/Code&gt;
        &lt;Message&gt;Query-string authentication version 4 requires the X-Amz-Algorithm, X-Amz-Credential, X-Amz-Signature, X-Amz-Date, X-Amz-SignedHeaders, and X-Amz-Expires parameters.&lt;/Message&gt;
        &lt;RequestId&gt;{requestId}&lt;/RequestId&gt;
        &lt;HostId&gt;{hostId}&lt;/HostId&gt;
    &lt;/Error&gt;

Is there some way I get the error while generating the preSignedUrl so that I don't have to try and upload the file.

    AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(&quot;accessKey&quot;, &quot;secretKey&quot;)))
                    .withRegion(clientRegion)
                    .build();
    
    GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, objectKey)
     .withMethod(HttpMethod.PUT)
     .withExpiration(expiration);

    URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);

答案1

得分: 1

生成预签名URL无需API调用;它可以由框架使用指定的访问密钥和秘钥生成。

当接收到请求时,生成的URL将由S3进行验证,只有在生成它时使用了有效凭据时才会被接受。

底线是:为了验证您的凭据,您需要进行实际执行调用AWS的API请求。这几乎可以是您的s3Client上的任何其他方法。

英文:

Generating a pre-signed URL doesn't require an API call; it can be generated by the framework using the specified access key and secret.

The generated URL will be validated by S3 when the request is received, and will obviously only be accepted when valid credentials were used for generating it.

Bottom line: in order to validate your credentials you need to make an API request that actually performs a call to AWS. This can be pretty much any other method on your s3Client.

答案2

得分: 0

开始吧:

.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("accessKey", "secretKey")))

静态凭证违反了AWS最佳实践。相反,应该依赖通过环境变量或执行角色提供的凭证(在运行于EC2、ECS或Lambda上时)。

你能验证凭证是否有效的唯一方法是尝试使用它们。你可以编写一个小的虚拟文件,但是这可能会对任何应该读取该文件的内容造成问题,因为S3上的最终一致性问题。

还有一个问题是你给URL设置的过期时间可能与凭证的生命周期不对应。

解决所有这些问题的最佳方案是创建一个有权在S3上进行PUT操作的角色,并且角色的持续时间与URL的过期时间一致(请注意,最长持续时间为12小时),然后显式地假定该角色以构建请求:

final String assumedRoleArn = "arn:aws:iam::123456789012:role/Example";
final String sessionName = "example";
final String bucketName = "com-example-mybucket";
final String objectKey = "myfile.txt";

final int expirationSeconds = 12 * 3600;
final Date expiresAt = new Date(System.currentTimeMillis() + expirationSeconds * 1000);

AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.defaultClient();

AWSCredentialsProvider credentialsProvider = new STSAssumeRoleSessionCredentialsProvider.Builder(assumedRoleArn, sessionName)
                                             .withStsClient(stsClient)
                                             .withRoleSessionDurationSeconds(expirationSeconds)
                                             .build();

AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(credentialsProvider).build();

URL presignedUrl = s3Client.generatePresignedUrl(bucketName, objectKey, expiresAt, HttpMethod.PUT);
英文:

Let's start with this:

.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(&quot;accessKey&quot;, &quot;secretKey&quot;)))

Static credentials go against AWS best practice. Instead, rely on credentials provided via environment variables or an execution role (when running on EC2, ECS, or Lambda).

The only way that you can verify that the credentials are valid is to try them. You could write a small dummy file, however this may cause problems for anything that is supposed to read that file, due to eventual consistency on S3.

There's also the problem that the expiration that you give the URL may not correspond to the lifetime of the credentials.

The best solution to all of these problems is to create a role that has access to PUT the files on S3, and has a duration consistent with your URL expiration (note that the maximum is 12 hours), then explicitly assume that role in order to construct the request:

final String assumedRoleArn = &quot;arn:aws:iam::123456789012:role/Example&quot;;
final String sessionName = &quot;example&quot;;
final String bucketName = &quot;com-example-mybucket&quot;;
final String objectKey = &quot;myfile.txt&quot;;

final int expirationSeconds = 12 * 3600;
final Date expiresAt = new Date(System.currentTimeMillis() + expirationSeconds * 1000);

AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.defaultClient();

AWSCredentialsProvider credentialsProvider = new STSAssumeRoleSessionCredentialsProvider.Builder(assumedRoleArn, sessionName)
                                             .withStsClient(stsClient)
                                             .withRoleSessionDurationSeconds(expirationSeconds)
                                             .build();

AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(credentialsProvider).build();

URL presignedUrl = s3Client.generatePresignedUrl(bucketName, objectKey, expiresAt, HttpMethod.PUT);

huangapple
  • 本文由 发表于 2020年8月21日 20:24:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/63522895.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定