You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS SDK v3 Node.js 18调用KMS解密S3文件遇byteLength未定义错误

问题原因
  1. 对SSE-KMS机制的误解:你用--sse aws:kms上传的对象属于服务器端加密,下载时AWS S3会自动通过对应的KMS密钥解密,返回明文内容,根本不需要手动调用KMS的Decrypt接口。
  2. 代码的直接错误:AWS SDK v3中GetObjectCommand返回的Body是ReadableStream对象,而KMS的DecryptCommand要求CiphertextBlob必须是Buffer或Uint8Array类型,直接传递Stream会触发序列化错误,也就是你看到的Cannot read properties of undefined (reading 'byteLength')。
解决方案

方案一:正确处理SSE-KMS对象下载(推荐)

既然SSE-KMS对象下载时自动解密,只需读取S3返回的流并转换成可处理的格式即可:

const { S3Client, GetObjectCommand } = require("@aws-sdk/client-s3");
const fs = require('fs');
const { pipeline } = require('stream/promises');

const s3Client = new S3Client({ region: 'ap-south-1' }); 
const s3Bucket = 'lambda-config';
const s3ObjectKey = 'config.json';

const outputFilePath = 'decrypted.txt';

async function fetchAndSaveFile() {
  const getObjectParams = {
    Bucket: s3Bucket,
    Key: s3ObjectKey
  };

  try {
    const { Body } = await s3Client.send(new GetObjectCommand(getObjectParams));
    // 直接将流写入文件
    await pipeline(Body, fs.createWriteStream(outputFilePath));
    console.log('文件已保存到', outputFilePath);
  } catch (error) {
    console.error('操作失败:', error);
  }
}

fetchAndSaveFile();

如果需要先将流转换成Buffer处理:

async function fetchFileFromS3(bucket, objectKey) {
  const getObjectParams = {
    Bucket: bucket,
    Key: objectKey
  };

  try {
    const { Body } = await s3Client.send(new GetObjectCommand(getObjectParams));
    // 将ReadableStream转换为Buffer
    const chunks = [];
    for await (const chunk of Body) {
      chunks.push(chunk);
    }
    return Buffer.concat(chunks);
  } catch (error) {
    console.error('从S3获取文件失败:', error);
    throw error;
  }
}

// 使用示例
fetchFileFromS3(s3Bucket, s3ObjectKey)
  .then(buffer => {
    fs.writeFileSync(outputFilePath, buffer);
    console.log('文件已保存');
  })
  .catch(err => console.error(err));

方案二:仅适用于客户端加密场景的手动解密

如果你是客户端加密后上传的对象(而非SSE-KMS),需要先把S3的Body转换成Buffer,再传给KMS:

const { S3Client, GetObjectCommand } = require("@aws-sdk/client-s3");
const { KMSClient, DecryptCommand } = require("@aws-sdk/client-kms");
const fs = require('fs');

const s3Client = new S3Client({ region: 'ap-south-1' }); 
const kmsClient = new KMSClient({ region: 'ap-south-1' }); 

const s3Bucket = 'lambda-config';
const s3ObjectKey = 'config.json';
const keyId = 'my_kms_key_id';

async function fetchFileFromS3(bucket, objectKey) {
  const getObjectParams = {
    Bucket: bucket,
    Key: objectKey
  };

  try {
    const { Body } = await s3Client.send(new GetObjectCommand(getObjectParams));
    // 将Stream转换为Buffer
    const chunks = [];
    for await (const chunk of Body) {
      chunks.push(chunk);
    }
    return Buffer.concat(chunks);
  } catch (error) {
    console.error('从S3获取文件失败:', error);
    throw error;
  }
}

async function decryptData(encryptedData) {
  const decryptParams = {
    CiphertextBlob: encryptedData,
    KeyId: keyId // 密钥上下文明确时可省略
  };

  try {
    const { Plaintext } = await kmsClient.send(new DecryptCommand(decryptParams));
    return Plaintext;
  } catch (error) {
    console.error('解密失败:', error);
    throw error;
  }
}

const outputFilePath = 'decrypted.txt';

fetchFileFromS3(s3Bucket, s3ObjectKey)
  .then(async (fileData) => {
    const decryptedData = await decryptData(fileData);
    fs.writeFileSync(outputFilePath, decryptedData);
    console.log('解密后的数据已写入', outputFilePath);
  })
  .catch(error => {
    console.error('发生错误:', error);
  });
关键说明
  • SSE-KMS模式下,只要你的IAM角色拥有s3:GetObject和kms:Decrypt(对应目标KMS密钥)权限,下载时S3会自动返回明文,无需额外操作。
  • AWS SDK v3与v2的核心差异之一:S3的GetObject返回的Body从v2的Buffer变成了v3的ReadableStream,必须先转换为Buffer才能作为二进制数据传递给其他服务。

内容的提问来源于stack exchange,提问作者DhirajAswani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 21:09:59