19. 압축 패킷 해제 시 압축 폭탄(decompression bomb) 방어 (C#)

난이도 최상 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - 압축 패킷 해제 시 압축 폭탄(decompression bomb) 방어
// ----------------------------------------------------------------------------
// 시나리오 (프로토콜 · 서버-클라/서버-서버):
//   - 대역폭 절약을 위해 일부 패킷(채팅 히스토리, 맵 청크, 배치 업데이트 등)은 압축돼 온다.
//     와이어 포맷: [u32 compressedLen][u32 originalLen][compressedLen 바이트 압축 데이터].
//   - originalLen 은 "보낸 쪽이 선언한 원본 크기" 다(신뢰 불가, 공격자 제어 가능).
//   - 서버는 DeflateStream 으로 풀어 원본 바이트를 얻는다.
//   - 공격자는 작은 압축 데이터가 거대한 원본으로 팽창하는 "압축 폭탄" 을 만들 수 있다.
//
// 요구사항:
//   - 선언된 originalLen 을 신뢰해 거대한 버퍼를 선할당하면 안 된다(over-allocation DoS 금지).
//   - 압축 해제 출력 총량에 상한이 있어야 한다(ratio/absolute bomb DoS 금지).
//   - compressedLen 이 실제 수신 버퍼 경계를 넘으면 안 된다.
//   - 풀어낸 실제 크기와 선언 크기의 일치(또는 정책 위반 시 거부)를 검증해야 한다.
//
// 과제:
//   이 코드의 잠재적 문제를 모두 찾고, 왜/어떻게 작은 패킷으로 OOM/CPU 고갈이 일어나는지
//   설명하고, 수정안과 더 나은 설계를 제시하라.
//   (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

using System;
using System.IO;
using System.IO.Compression;

public static class PacketCompression
{
    private static uint ReadU32(byte[] b, int off)
    {
        return (uint)(b[off] | (b[off + 1] << 8) | (b[off + 2] << 16) | (b[off + 3] << 24));
    }

    // 압축 패킷을 풀어 원본 바이트를 돌려준다.
    public static byte[] DecompressPacket(byte[] buf)
    {
        uint compressedLen = ReadU32(buf, 0);
        uint originalLen   = ReadU32(buf, 4);   // 보낸 쪽이 선언한 원본 크기

        // (A) 선언된 originalLen 으로 출력 버퍼 즉시 선할당 (신뢰)
        var preallocated = new byte[originalLen];

        // (D) compressedLen 이 실제 버퍼 경계 안인지 검사 안 함
        using var input = new MemoryStream(buf, 8, (int)compressedLen);
        using var inflate = new DeflateStream(input, CompressionMode.Decompress);
        using var outStream = new MemoryStream();

        // (B) 출력 총량 상한 없이 끝까지 전부 복사 — 압축 폭탄에 그대로 노출
        inflate.CopyTo(outStream);

        // (C) produced 와 originalLen 일치 검증 없음, 압축비 상한 없음
        return outStream.ToArray();
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.