Files
KArtSell.Aegis/docs/Design/kbx-foundation-v36/backend/Shared/Excel/XlsxSafetyInspector.cs
T

34 lines
1.6 KiB
C#

using System.IO.Compression;
namespace Shared.Excel;
public sealed class XlsxSafetyInspector
{
public const long DefaultMaxUncompressedBytes = 250L * 1024 * 1024;
public const int DefaultMaxEntries = 5_000;
public void EnsureSafe(byte[] bytes, long maxUncompressedBytes = DefaultMaxUncompressedBytes, int maxEntries = DefaultMaxEntries)
{
using var stream = new MemoryStream(bytes, writable: false);
using var archive = new ZipArchive(stream, ZipArchiveMode.Read, leaveOpen: false);
if (archive.Entries.Count == 0 || archive.Entries.Count > maxEntries)
throw new InvalidDataException("Excel 파일 내부 구조가 비정상적입니다.");
if (!archive.Entries.Any(x => x.FullName.Equals("[Content_Types].xml", StringComparison.OrdinalIgnoreCase)) ||
!archive.Entries.Any(x => x.FullName.Equals("xl/workbook.xml", StringComparison.OrdinalIgnoreCase)))
throw new InvalidDataException("유효한 .xlsx 통합문서가 아닙니다.");
long total = 0;
foreach (var entry in archive.Entries)
{
total = checked(total + entry.Length);
if (total > maxUncompressedBytes)
throw new InvalidDataException("압축 해제된 Excel 데이터가 허용 크기를 초과합니다.");
// A very small compressed entry expanding to an extreme size is suspicious.
if (entry.CompressedLength > 0 && entry.Length > 10L * 1024 * 1024 && entry.Length / entry.CompressedLength > 200)
throw new InvalidDataException("비정상적인 압축률의 Excel 항목이 감지되었습니다.");
}
}
}