通过加密的S3存储桶上的预签名url的putObject返回的签名不匹配

时间:2018-11-30 16:34:29

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

我有无服务器的AWS Lambda,它将通过预签名的URL将对象获取/放到加密的S3存储桶中。 getObject工作完美。一旦加密存储桶并且我不明白为什么,putObject就会产生SignatureDoesNotMatch错误。我玩过标题等,但仍然无法正常使用。以下代码/政策:

lambda

    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 (原始问题没有serversidencryption标头)

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”

1 个答案:

答案 0 :(得分:1)

引用Server Side Encryption文档:

  

您不能对使用以下命令上传的对象实施SSE-S3加密   预设网址。您只能使用   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);
  }
});