从 s3 签名 url 以使用 SSE-C 解密上传的对象

Getting signed url from s3 to decrypt uploaded object using SSE-C

我使用以下代码段成功加密并上传了图像文件:

var ssecKey = '12345678901234567890123456789012'

var data = {
    Key: 'testfolder/abc.png', 
    Body: buffer,
    ContentEncoding: 'base64',
    ContentType: 'image/png',
    SSECustomerAlgorithm: 'AES256',
    SSECustomerKey: ssecKey
};

s3.putObject(data, (err) => {
    if (err) return console.error(err.stack)

    s3.getSignedUrl('getObject', {
        Key: 'testfolder/abc.png', 
        Expires: 160,
        SSECustomerAlgorithm: 'AES256',
        SSECustomerKey: ssecKey
    }, (err, data) => {
        if (err) return console.error(err.stack)

        console.log(data);
    });
});

为了取回解密后的对象,我使用了getsignedurl方法,控制台输出了一个签名的url但是没有解密图片,因此在浏览器上显示如下错误:

我这里可能做错了什么。

使用 getObject 而不是 getSignedUrl。

我认为不使用 getSignedUrl 方法返回解密数据是有道理的。由于使用 getSignedUrl,密钥将在 url 中以纯文本形式传递,而不是在 header 中传递,如果密钥可通过网络读取,这将减少加密的使用。

以下使用字节数组中解密的 object:

    s3.getObject({
        Key: 'testfolder/abc.png',
        SSECustomerAlgorithm: 'AES256',
        SSECustomerKey: ssecKey
    }, function (err, data) {
        if (err) {
            console.error(err);
        }
        else {
            console.log('BYTE ARRAY: ' + data.Body);
            console.log('BASE64: ' + data.Body.toString('base64'));
        }
    });

根据 https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property 上的文档:

Note:

Not all operation parameters are supported when using pre-signed URLs. Certain parameters, such as SSECustomerKey, ACL, Expires, ContentLength, or Tagging must be provided as headers when sending a request. If you are using pre-signed URLs to upload from a browser and need to use these fields, see createPresignedPost().

您需要这样的代码:

在后端:

AWS.config.update({
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  region: process.env.AWS_REGION,
  signatureVersion: 'v4' // NB! this seems needed to avoid some bugs
})
s3.getSignedUrl('getObject', {
      Bucket: process.env.S3_BUCKET_NAME,
      Key: key,
      SSECustomerAlgorithm: 'AES256', // NB! this must be added
    })

在浏览器中:

//encryption key can be generated in nodejs:
//var password = "some easy to remember password";
//var encryption_key = crypto.createHash('sha256').update(password, 'utf8').digest('base64');
//var encryption_key_md5 = crypto.createHash('md5').update(encryption_key, 'base64').digest('base64');

function presigned_get(url) {
  console.log("presigned_get", url);
  var xhr = new XMLHttpRequest();
  xhr.responseType = 'blob';
  xhr.open("get", url);
  xhr.setRequestHeader("x-amz-server-side-encryption-customer-algorithm", "AES256");
  xhr.setRequestHeader("x-amz-server-side-encryption-customer-key", ENCRYPTION_KEY);
  //xhr.setRequestHeader("x-amz-server-side-encryption-customer-key-MD5", ENCRYPTION_KEY_MD5);
  xhr.send();
  xhr.onload = function() {
    if (xhr.status == 200) {
      console.log(`Downloaded ${url}`);
      var filename = url.substring(0, url.indexOf('?'));
      filename = filename.substring(filename.lastIndexOf('/')+1);
      window.saveAs(xhr.response, filename);
    } else {
      var reader = new FileReader();
      reader.readAsText(xhr.response);
      reader.addEventListener('loadend', (e) => {
        console.error(`Downloading ${url} failed:`, xhr.statusText, e.srcElement.result);
      });
    }
  }
}