44. 재생 방지 슬라이딩 윈도우 비트맵의 시프트·경계 결함 (C#)

난이도 상 해설 보기 →

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

결함 코드 · C#
// 시나리오: 신뢰성 UDP + 세션 암호화 게임 프로토콜의 재생 공격 방지(anti-replay).
//   - 각 암호화 패킷에는 세션 내 단조 증가 시퀀스 번호(seq, 64비트)가 붙는다.
//   - UDP 특성상 패킷은 재정렬·중복되어 도착할 수 있으므로, "이미 처리한 seq"를
//     64칸 슬라이딩 윈도우 비트맵으로 추적해 재생/중복을 걸러낸다.
//   - _highest 는 지금까지 받은 가장 큰 seq. 비트맵의 비트 i 는 seq (_highest - i) 를
//     이미 받았음을 뜻한다(비트 0 = _highest 자신).
//
// 요구사항:
//   1) 같은 seq 를 두 번(재생/중복) 받으면 거부한다.
//   2) 윈도우(64칸) 안에서 도착 순서가 뒤바뀐 새 seq 는 수용한다.
//   3) 윈도우보다 더 오래된(너무 뒤처진) seq 는 재생 여부를 판별할 수 없으므로 거부한다.
//   4) seq 가 크게 점프해도(윈도우를 통째로 넘어가도) 상태가 일관돼야 한다.
//
// 과제: CheckAndUpdate 를 검토하여 요구사항 1·3·4가 깨지는 지점을 (A)(B) 마커로
//       진단하고, 정확한 수정안과 더 나은 설계를 제시하라.

public sealed class AntiReplayWindow
{
    private ulong _bitmap;      // 비트 i = seq (_highest - i) 수신됨
    private ulong _highest;     // 지금까지 최대 seq
    private bool _init;

    public bool CheckAndUpdate(ulong seq)
    {
        if (!_init) { _init = true; _highest = seq; _bitmap = 1UL; return true; }

        if (seq > _highest)
        {
            ulong shift = seq - _highest;
            _bitmap = _bitmap << (int)shift;   // (A) 윈도우를 shift 칸 전진
            _bitmap |= 1UL;                    //     새 최고 seq 표시
            _highest = seq;
            return true;
        }
        else
        {
            ulong diff = _highest - seq;
            if (diff >= 64)
                return true;                   // (B) 윈도우 밖(오래된) 패킷 처리

            ulong mask = 1UL << (int)diff;
            if ((_bitmap & mask) != 0)
                return false;                  // 이미 받은 seq
            _bitmap |= mask;
            return true;
        }
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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