36. 압축 해제(decompression bomb)의 크기 상한·비율 검증 부재 (C#)
난이도 상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// 시나리오: 게임 프로토콜 — 압축된 패킷 프레임의 해제(decompression)
//
// 대역폭 절약을 위해 큰 페이로드(맵 스냅샷, 인벤토리 대량 동기화 등)는 압축해서
// 보낸다. 프레임 구조는 [uint32 declaredSize][compressed bytes...] 이며,
// declaredSize 는 "해제 후 크기"를 알려주는 힌트다. 서버는 이를 받아 해제한다.
//
// 요구사항:
// - 신뢰할 수 없는 클라이언트 입력을 파싱한다(악의적 바이트/압축 가정).
// - 한 연결/한 프레임이 서버 메모리를 위협할 만큼 큰 데이터를 만들 수 없어야 한다.
// - 해제 실패·비정상 크기는 안전하게 거부하고 연결을 종료한다.
//
// 아래 해제 코드를 검토하라.
using System;
using System.IO;
using System.IO.Compression;
public static class PacketCodec
{
// 프레임에서 declaredSize 와 압축 바이트를 읽어 해제한 원본을 돌려준다.
public static byte[] Decompress(byte[] frame)
{
int declaredSize = BitConverter.ToInt32(frame, 0); // (A) 해제 후 크기 힌트
var output = new byte[declaredSize]; // (B) 힌트대로 버퍼 할당
using var input = new MemoryStream(frame, 4, frame.Length - 4);
using var deflate = new DeflateStream(input, CompressionMode.Decompress);
int total = 0;
int n;
while ((n = deflate.Read(output, total, output.Length - total)) > 0) // (C)
total += n;
return output;
}
} 결함 코드 · C++
// 시나리오: 게임 프로토콜 — 압축된 패킷 프레임의 해제(decompression) (C++)
//
// 큰 페이로드(맵 스냅샷, 인벤토리 대량 동기화)는 압축해서 보낸다. 프레임 구조는
// [uint32 declaredSize][compressed bytes...] 이며, declaredSize 는 "해제 후 크기"
// 힌트다. 서버는 이를 받아 해제한다.
//
// 요구사항:
// - 신뢰할 수 없는 클라이언트 입력을 파싱한다(악의적 바이트/압축 가정).
// - 한 프레임이 서버 메모리를 위협할 만큼 큰 데이터를 만들 수 없어야 한다.
// - 해제 실패·비정상 크기는 안전하게 거부한다.
//
// Inflate() 는 zlib inflate 를 흉내낸 자리표시자다:
// 실제 해제된 바이트 수를 반환하고, 최대 outCap 바이트까지 out 에 쓴다.
// (단, 아래 호출은 outCap 을 declaredSize 로 넘긴다.)
// 아래 해제 코드를 검토하라.
#include <cstdint>
#include <cstring>
#include <vector>
// 압축 입력을 해제해 out[0..outCap) 에 쓰고, 실제 해제 총 바이트 수를 반환.
extern size_t Inflate(const uint8_t* in, size_t inLen, uint8_t* out, size_t outCap);
class PacketCodec {
public:
// 프레임에서 declaredSize 와 압축 바이트를 읽어 해제한 원본을 돌려준다.
static std::vector<uint8_t> Decompress(const uint8_t* frame, size_t frameLen) {
uint32_t declaredSize;
std::memcpy(&declaredSize, frame, 4); // (A) 해제 후 크기 힌트
std::vector<uint8_t> output(declaredSize); // (B) 힌트대로 버퍼 할당
size_t produced = Inflate(frame + 4, frameLen - 4, // (C)
output.data(), declaredSize);
output.resize(produced);
return output;
}
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.