C# AWS Lambda读取S3中AES加密Excel文件的解密问题
Excel文件解密失败问题分析与修复方案
问题背景
AWS S3存储桶中存放了自定义加密的CSV文件,基于C#/.NET 6的Lambda函数通过AesManaged解密后转UTF-8编码上传,流程对CSV完全正常。新增Excel(xls/xlsx)支持时,无报错但解密后文件仍处于加密状态,格式与扩展名不匹配,转CSV尝试也未成功。
核心问题定位
现有代码错误地将二进制格式的Excel文件当成文本文件处理:
- 对解密后的Excel流执行了
Encoding.Convert编码转换,破坏了二进制文件的结构 - 使用
StreamReader读取二进制流,引入编码猜测,进一步损坏原始数据 - CSV是文本文件,编码转换逻辑适用,但Excel是二进制格式,完全不兼容这套处理流程
修复步骤
- 区分文件类型处理:根据文件名后缀判断是CSV还是Excel,分别执行不同的流处理逻辑
- Excel文件直接保留二进制流:解密后直接复制原始二进制流,不做任何编码转换
- 确保流位置正确:上传前重置流的Position到开头,避免数据读取不全
- 替换过时的Aes实现:将
AesManaged替换为.NET 6推荐的Aes.Create()
修改后的代码示例
主流程修改
var ddresult = DownloadAndDecrypt(s3client, bucketName, fileName, credInput); MemoryStream tempms = null; if (ddresult.Stream != null) { var fileExt = Path.GetExtension(fileName).ToLowerInvariant(); if (fileExt == ".csv") { // CSV文件沿用原有文本编码转换逻辑 var resultms = new MemoryStream(); CopyStream(ddresult.Stream, resultms); resultms.Position = 0; // 重置流位置,确保StreamReader能读取到内容 var encBytes = resultms.ToArray(); using var sr = new StreamReader(resultms); var encoding = sr.CurrentEncoding; var utf8Bytes = Encoding.Convert(encoding, Encoding.UTF8, encBytes); tempms = new MemoryStream(utf8Bytes); } else if (fileExt is ".xls" or ".xlsx") { // Excel文件直接复制解密后的二进制流,跳过编码转换 tempms = new MemoryStream(); CopyStream(ddresult.Stream, tempms); tempms.Position = 0; } } if (tempms != null) { var s3uploadresult = WriteFileToS3(newBucketName, fileName, tempms, s3Client); tempms.Dispose(); // 手动释放资源,Lambda环境中避免泄漏 }
DownloadAndDecrypt方法优化
public StreamResultModel DownloadAndDecrypt(AmazonS3Client s3Client, string bucketName, string filename, CredInputModel credInput) { var result = new StreamResultModel { Error = false }; try { using var transferUtility = new TransferUtility(s3Client); var request = new TransferUtilityOpenStreamRequest { BucketName = bucketName, Key = filename, }; var originalStream = transferUtility.OpenStream(request); // 替换为.NET官方推荐的非过时Aes实现 using var aes = Aes.Create(); aes.BlockSize = 128; aes.KeySize = 256; aes.Mode = CipherMode.CBC; aes.Key = Convert.FromBase64String(credInput.KeySharedSecret); aes.IV = Convert.FromBase64String(credInput.Salt); var decryptor = aes.CreateDecryptor(); result.Stream = new CryptoStream(originalStream, decryptor, CryptoStreamMode.Read); return result; } catch (Exception e) { result.Error = true; result.ErrorMsg = e.Message; return result; } }
额外建议
- 增加日志记录:记录解密前后的流长度,验证解密是否成功(解密后Excel流长度应与原始未加密文件一致)
- 完善错误处理:针对Excel文件添加格式校验,避免无效文件上传
- 资源管理:使用
using语句自动管理流资源,Lambda环境中减少资源泄漏风险
内容的提问来源于stack exchange,提问作者Joseph Robinson
相关产品推荐
相关产品推荐

