44. UDP 연결 마이그레이션의 경로 검증 부재 (세션 탈취·오배달, C#)

난이도 중 해설 보기 →

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

결함 코드 · C#
// 시나리오: UDP 기반 실시간 게임 서버의 세션 라우팅과 "연결 마이그레이션".
//   - 클라이언트는 로그인 시 발급받은 connectionId(암호학적으로 큰 난수)를 매 패킷 헤더에 담는다.
//   - UDP 라 소스 주소(IP:포트)는 NAT 리바인딩·모바일 네트워크 전환으로 세션 도중 바뀔 수 있다.
//   - 그래서 서버는 connectionId 로 세션을 찾고, 패킷이 새 주소에서 오면 세션의 원격 주소를
//     그 주소로 갱신해 이후 송신을 그쪽으로 보낸다(연결 마이그레이션).
//
// 요구사항:
//   1) 세션의 원격 주소를 바꿀 때는, 그 새 경로가 실제로 정당한 피어인지 검증해야 한다.
//   2) connectionId 만으로 원격 주소를 즉시 신뢰해 갱신하면 안 된다(스푸핑/탈취 위험).
//   3) 마이그레이션 검증이 끝나기 전까지는 기존(검증된) 경로로 계속 송신한다.
//
// 과제: OnPacket 을 검토하여 요구사항 1~3이 깨지는 지점을 (A)(B) 마커로 진단하고,
//       정확한 수정안과 더 나은 설계를 제시하라.

using System.Net;

public sealed class Session
{
    public long ConnId;
    public IPEndPoint Remote;      // 현재 송신 대상 주소
    public byte[] Key;             // AEAD 세션 키
    public void Dispatch(byte[] plaintext) { /* 게임 로직 처리 */ }
    public void SendTo(IPEndPoint ep, byte[] data) { /* UDP 송신 */ }
}

public sealed class UdpSessionRouter
{
    private readonly System.Collections.Generic.Dictionary<long, Session> _byConn = new();

    public void Register(Session s) { _byConn[s.ConnId] = s; }

    // 소켓 수신 콜백: 하나의 UDP 데이터그램 도착.
    public void OnPacket(IPEndPoint source, long connId, byte[] frame)
    {
        if (!_byConn.TryGetValue(connId, out var s))
            return;

        if (!s.Remote.Equals(source))
        {
            s.Remote = source;                 // (A) 새 주소로 즉시 원격 갱신(마이그레이션)
        }

        byte[] plaintext = AeadOpen(s.Key, frame);
        if (plaintext == null)
            return;

        s.Dispatch(plaintext);                 // (B) 갱신된 remote 로 처리·이후 송신
    }

    private static byte[] AeadOpen(byte[] key, byte[] frame)
    {
        // 복호화+인증 성공 시 평문, 실패 시 null (구현 생략)
        return frame;
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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