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++
// 시나리오: 신뢰성 UDP + 세션 암호화 게임 프로토콜의 재생 공격 방지(anti-replay) — C++ 서버.
// - 각 패킷에 세션 내 단조 증가 seq(64비트). UDP라 재정렬/중복 도착 가능.
// - 64칸 슬라이딩 윈도우 비트맵으로 이미 처리한 seq 를 추적한다.
// - highest_ = 최대 수신 seq, 비트 i = seq (highest_ - i) 를 받았음(비트0 = highest_).
//
// 요구사항:
// 1) 같은 seq 재수신(재생/중복)은 거부.
// 2) 윈도우(64칸) 내 재정렬된 새 seq 는 수용.
// 3) 윈도우보다 오래된 seq 는 판별 불가이므로 거부.
// 4) seq 가 윈도우를 통째로 넘겨 점프해도 상태 일관.
//
// 과제: checkAndUpdate 를 검토하여 요구사항 1·3·4가 깨지는 지점을 (A)(B) 마커로 진단하고,
// 정확한 수정안과 더 나은 설계를 제시하라.
//
// 컴파일: g++ -std=c++17 -fsyntax-only problem.cpp
#include <cstdint>
class AntiReplayWindow
{
public:
bool checkAndUpdate(std::uint64_t seq)
{
if (!init_) { init_ = true; highest_ = seq; bitmap_ = 1ULL; return true; }
if (seq > highest_)
{
std::uint64_t shift = seq - highest_;
bitmap_ = bitmap_ << shift; // (A) 윈도우를 shift 칸 전진
bitmap_ |= 1ULL; // 새 최고 seq 표시
highest_ = seq;
return true;
}
else
{
std::uint64_t diff = highest_ - seq;
if (diff >= 64)
return true; // (B) 윈도우 밖(오래된) 패킷 처리
std::uint64_t mask = 1ULL << diff;
if ((bitmap_ & mask) != 0)
return false; // 이미 받은 seq
bitmap_ |= mask;
return true;
}
}
private:
std::uint64_t bitmap_ = 0;
std::uint64_t highest_ = 0;
bool init_ = false;
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.