putObject via presigned url on encrypted S3 bucket returns 签名不匹配
putObject via presigned url on encrypted S3 bucket returns signature does not match
我有无服务器 aws lambda,它将通过预先签名的 url get/put object 到加密的 S3 存储桶。 getObject 完美地工作。一旦我加密存储桶,putObject 就会生成 SignatureDoesNotMatch
错误,我不明白为什么。我玩过 headers 之类的,但仍然无法正常工作。以下代码/政策:
λ
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 });
}
});
}
调用代码在这里:
生成预签名 Url
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(原题没有serversidencryptionheader)
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"
引用 Server Side Encryption 文档:
You can't enforce SSE-S3 encryption on objects that are uploaded using
presigned URLs. You can specify server-side encryption only with the
AWS Management Console or an HTTP request header. For more
information, see Specifying Conditions in a Policy.
我能够得到类似的东西。我需要使用 PUT 而不是 POST,并且我需要提供 x-amz-server-side-encryption:AES256
作为 header,如下所示:
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);
}
});
我有无服务器 aws lambda,它将通过预先签名的 url get/put object 到加密的 S3 存储桶。 getObject 完美地工作。一旦我加密存储桶,putObject 就会生成 SignatureDoesNotMatch
错误,我不明白为什么。我玩过 headers 之类的,但仍然无法正常工作。以下代码/政策:
λ
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 });
}
});
}
调用代码在这里:
生成预签名 Url
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(原题没有serversidencryptionheader)
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"
引用 Server Side Encryption 文档:
You can't enforce SSE-S3 encryption on objects that are uploaded using presigned URLs. You can specify server-side encryption only with the AWS Management Console or an HTTP request header. For more information, see Specifying Conditions in a Policy.
我能够得到类似的东西。我需要使用 PUT 而不是 POST,并且我需要提供 x-amz-server-side-encryption:AES256
作为 header,如下所示:
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);
}
});