【问题标题】:putObject via presigned url on encrypted S3 bucket returns signature does not matchputObject 通过加密 S3 存储桶上的预签名 url 返回签名不匹配
【发布时间】:2019-05-02 20:13:12
【问题描述】:

我有无服务器的 aws lambda,它将通过预签名的 url 将对象获取/放入加密的 S3 存储桶。 getObject 完美运行。一旦我加密存储桶,putObject 就会生成SignatureDoesNotMatch 错误,我无法理解为什么。我玩过头球等,但仍然无法让它发挥作用。以下代码/政策:

λ

    const generatepresignedurl = (req, res, callback) => {

    var fileurls = [];
    const body = JSON.parse(req.body);
    const theBucket = body['theBucket'];
    const theKey = body['theKey'];
    const theContentType = body['theContentType'];
    const theOperation = body['theOperation'];

    /*setting the presigned url expiry time in seconds, also check if user making the request is an authorized user
     for your app (this will be specific to your app’s auth mechanism so i am skipping it)*/
    const signedUrlExpireSeconds = 60 * 60;

    if (theOperation == 'getObject') {
        var params = {
            Bucket: theBucket,
            Key: theKey,
            Expires: signedUrlExpireSeconds
        };
    } else {
        var params = {
            Bucket: theBucket,
            Key: theKey,
            Expires: signedUrlExpireSeconds,
            ACL: 'bucket-owner-full-control',
            ContentType: theContentType,
            ServerSideEncryption: 'AES256'
        };
    }

    s3.getSignedUrl(theOperation, params, function (err, url) {
        if (err) {
            console.log('Error Getting Presigned URL from AWS S3');
            // callback(null, ({ success: false, message: 'Pre-Signed URL error', urls: fileurls }));
            callback(null, {error: err});
        }
        else {
            fileurls[0] = url;
            console.log('Presigned URL: ', fileurls[0]);
            callback(null, { success: true, message: 'AWS SDK S3 Pre-signed urls generated successfully.', urls: fileurls });
        }
    });

}

调用代码在这里:

生成预签名网址

Function callStandAloneAWSService(lambda As String, request As String, contentType As String) As String

    Dim httpserver As New MSXML2.XMLHTTP

    With httpserver

        Dim theURL As String
        theURL = AWS_WEBSERVICE_URL_DEV

        .Open "POST", theURL & lambda 'variable that contains generatepresignedurl

        .setRequestHeader "Content-type", contentType

        .send request

        Do: DoEvents: Loop Until .readyState = 4 'make sure we are ready to recieve response

        callStandAloneAWSService = .responseText

    End With

End Function

上传到 PreSigned URL(原始问题没有 serveridencryption 标头)

Function uploadToPreSignedURL(url As String, whichFile As String, contentType) As Boolean

    'code to create binaryFile

    Dim httpserver As New MSXML2.XMLHTTP

    With httpserver

        .Open "POST", url
        .setRequestHeader "Content-type", "text/plain" 'contentType
        .send binaryFile
        Do: DoEvents: Loop Until .readyState = 4 'make sure we are ready to recieve response

        If Len(.responseText) = 0 Then

            uploadToPreSignedURL = True

        Else

            'extract error message from xml and write to report mail

        End If

    End With

End Function

存储桶政策

{
    "Version": "2012-10-17",
    "Id": "S3PolicyId1",
    "Statement": [
        {
            "Sid": "DenyIncorrectEncryptionHeader",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::mybiggetybucket/*",
            "Condition": {
                "StringNotEquals": {
                    "s3:x-amz-server-side-encryption": "AES256"
                }
            }
        },
        {
            "Sid": "DenyUnEncryptedObjectUploads",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::mybiggetybucket/*",
            "Condition": {
                "Null": {
                    "s3:x-amz-server-side-encryption": "true"
                }
            }
        }
    ]
}

FWIW,我可以通过 aws cli 运行它并让它工作:

aws s3api put-object --bucket mybiggetybucket --key test.json --body package-lock.json --server-side-encryption "AES256"

【问题讨论】:

  • 如果您暂时禁止 S3 存储桶策略,您的上传是否有效?
  • @jarmod 是的,确实如此。

标签: vba amazon-web-services encryption amazon-s3 pre-signed-url


【解决方案1】:

引用Server Side Encryption 文档:

您无法对通过以下方式上传的对象强制执行 SSE-S3 加密 预签名的 URL。您只能使用 AWS 管理控制台或 HTTP 请求标头。更多 信息,请参阅Specifying Conditions in a Policy

我能够得到类似的工作。我需要使用 PUT 而不是 POST,并且需要提供 x-amz-server-side-encryption:AES256 作为标头,如下所示:

const axios = require('axios');
const AWS = require('aws-sdk');

const s3 = new AWS.S3();

const params = {
  Bucket: 'mybucket',
  Key: 'myfolder/myfile.txt',
  Expires: 60 * 60,
  ACL: 'bucket-owner-full-control',
  ContentType: 'text/plain',
  ServerSideEncryption: 'AES256',
};

const axiosConfig = {
  headers: {
    'Content-Type': 'text/plain',
    'x-amz-server-side-encryption': 'AES256',
  },
};

const uploadTextFile = (presignedurl) => {
  axios.put(presignedurl, 'some text here', axiosConfig).then((res) => {
    console.log('File uploaded');
  }).catch((error) => {
    console.error(error);
  });
};

s3.getSignedUrl('putObject', params, (err, url) => {
  if (err) {
    console.error(err);
  } else {
    console.log('Pre-signed URL:', url);
    uploadTextFile(url);
  }
});

【讨论】:

  • 当然!我什至没有想过尝试在我的调用中传递加密标头以获取签名 URL,即使我想尝试一下 :) ... 工作得很好!感谢上帝!这整个星​​期都困扰着我。
  • 您正在发出 PUT 并提供 SSE 标头,但由于原始签名问题而失败?还是别的什么?
  • 是的。同样的错误SignatureDoesNotMatch 无论我发出 PUT 还是 POST。我还将加密移动到 callPresignedURL 函数中,以准确模仿您回答的建议。
  • 确保凭据正确。确保您的签名请求和使用它的后续调用具有相同的 HTTP 标头。确保时钟已同步。
  • 对于所有追求最终解决方案的人来说,将加密标头 .setRequestHeader "x-amz-server-side-encryption", "AES256" 添加到 uploadToPreSignedURL 并从 Content-Type 中删除 Content-Type 标头,因为它已经在generatepresignedurl lambda 的参数。
猜你喜欢
  • 2019-01-27
  • 1970-01-01
  • 2014-09-01
  • 1970-01-01
  • 2021-08-18
  • 2019-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多