요약

  • TCP의 3방향 핸드셰이크는 실제 작업에 앞서 치르는 형식적 절차가 아니다. 이 절차의 주된 역사적 목적은 오래된 중복 SYN이 새 연결 시도로 오인되지 않도록 하는 것이다.
  • 각 엔드포인트는 자신의 초기 시퀀스 번호를 독자적으로 선택한다. 응답 측은 상대 번호에 대한 확인 응답과 자신의 SYN을 하나로 결합할 수 있지만, 발기 측은 응답 측의 현재 챌린지를 확인했음을 증명하는 세 번째 메시지를 보내야 한다.
  • 퀴어트 타임, TIME-WAIT, 비밀 오프셋 기반 ISN, SYN 쿠키는 인접한 문제들, 즉 오래된 데이터, 추측 가능한 번호, 조기 서버 상태를 해결한다. 어느 것도 TCP를 암호화된 상호 인증으로 바꾸지는 않는다.

엉뚱한 대화에서 온 패킷

인터네트워크는 패킷을 지연시키고, 중복시키고, 순서를 바꿀 수 있다. 그러므로 도착 사실만으로 정합성을 판단할 수는 없다. 두 애플리케이션이 TCP 연결을 닫은 직후 동일한 발신 주소, 발신 포트, 수신 주소, 수신 포트를 재사용한다고 상상해 보라. 이전 연결의 SYN이 새 연결이 시작되는 시점에도 네트워크를 떠돌고 있을 수 있다.

수신 측은 익숙한 4-튜플과 SYN 플래그를 보지만, 패킷의 겉모습만으로 과거를 읽어낼 수 없다. 이 세그먼트를 새 대화의 충분한 증거로 받아들인다면, 만료된 요청이 현재의 상태를 만들어 낼 수 있다.

1980년 1월에 발표된RFC 761은 이 문제를 시퀀스 공간의 관점에서 정리했다. 각 측은 자신의 초기 송신 시퀀스 번호를 선택하고 연결 수립 과정에서 상대 번호를 학습한다. 이 번호들은 이후 데이터의 순서를 정하고 중복을 거부하는 데 쓰이지만, 먼저 엔드포인트들이 어떤 번호가 이 세대(incarnation)에 속하는지 합의해야 한다.

세 메시지로 전달하는 네 가지 사실

동기화에는 논리적으로 네 가지 진술이 필요하다. 엔드포인트 A가 B에게 “내 시퀀스 번호는 X에서 시작한다”고 말하고, B가 X를 확인한다. B가 A에게 “내 번호는 Y에서 시작한다”고 말하고, A가 Y를 확인한다.

TCP는 가운데 두 진술을 하나의 세그먼트로 압축한다. A가SYN X를 보내면, B가SYN Y, ACK X+1로 응답하고, A는ACK Y+1을 돌려보낸다. 이것이 네 가지 사실이 세 메시지만으로 충분한 이유다.

이 산술에는 의미가 담겨 있다. SYN은 시퀀스 공간에서 한 자리를 차지하므로 다음 기대 번호는 X+1이다. 순수한 ACK는 시퀀스 번호를 소모하지 않는데, 그렇지 않으면 확인 응답 자체가 끝없는 확인 응답의 연쇄를 요구하게 된다.RFC 793은 1981년 9월 이 교환을 표준 연결 개시 상태 머신으로 정했다.

엔드포인트들은 전역 연결 레지스터를 조회하지 않는다. 모든 시퀀스 번호를 하나의 시계가 배정할 필요도 없다. 각 구현이 지역적으로 선택을 하고, 메시지가 그 선택들을 상호 가시적으로 만든다.

세 번째 메시지가 곧 증명이다

B의 SYN-ACK 이후에 멈추면 안 되는 이유는 무엇일까? B는 A의 번호를 확인했고, A는 B의 응답을 받았다. 그러나 B는 아직 A가 지금 이 SYN을 보냈는지 알지 못한다. 첫 SYN이 오래된 중복일 수 있고, B의 응답은 자신을 기억하지 못하는 호스트를 향해 이동하고 있을 수도 있다.

마지막 ACK가 이 증거 공백을 메운다. 이는 B에게, A의 현재 엔드포인트 상태를 제어하는 주체가 Y를 수신했으며 기대한 확인 응답을 돌려보냈음을 알려준다. RFC 761은 이를 기억과 메시지 사이의 절충으로 설명했다. B가 모든 엔드포인트 쌍에 대해 이전 번호의 완전한 이력을 보관할 수 없다면, 겉보기 발기 측에게 현재 교환을 검증하도록 요구하는 것이다.

이것은 신원 확인보다 좁은 개념이다. 정확히 확인된 시퀀스 번호는 TCP 모델 안에서의 수신 사실을 증명할 뿐이다. 그것은 기기를 조작하는 사람을 식별하지 않고, 애플리케이션 요청을 승인하지 않으며, 교환을 보고 수정할 수 있는 관찰자를 이기지도 못한다.

오래된 패킷에는 번호뿐 아니라 시간도 필요하다

핸드셰이크는 연결 개시를 보호하지만, 오래된 데이터는 개시 이후까지 남아 있을 수 있다. 그래서 TCP는 시퀀스 번호를 튜플뿐 아니라 시간에도 묶는다. 어떤 번호는 그 번호를 실은 세그먼트가 인터네트워크에 여전히 존재할 수 있는 동안 위험한 상태로 남는다.

초기 사양은 공학적 가정으로 최대 세그먼트 수명(MSL)을 2분으로 두었다. 호스트가 다운되어 최근 사용한 시퀀스 공간의 기억을 잃었다면, 새 세그먼트를 내보내기 전에 한 MSL 동안 조용히 있어야 했다. 기억을 보존했다면 이미 사용된 번호보다 뒤의 번호로 재개할 수 있었다.

정상 종료 이후에는 TIME-WAIT이 연결 식별자를 MSL의 두 배 동안 유지한다. 이 대기는 지연 세그먼트가 배수되도록 하고, 종료의 마지막 확인 응답이 재전송될 수 있게 한다. 기다림은 관료적 관성이 아니라, 오래된 패킷이 새 의미를 얻지 못하게 하는 상태다.

현재의 기본 사양인RFC 9293은 이 모델을 유지하되, 현대 시스템에서는 재부팅 퀴어트 타임이 대체로 불필요하다고 본다. 무작위화된 포트와 초기 번호가 우연한 재사용을 줄이고, 유효 패킷 수명은 더 짧아졌으며, 재부팅이 위험 구간보다 오래 걸리는 경우가 많기 때문이다. 높은 데이터 속도에서는 타임스탬프와 PAWS가 빠른 시퀀스 공간 순환을 다룬다. 실무적 처방이 바뀌어도 그 원칙은 살아 있다.

TIME-WAIT이 제 역할을 잊었을 때

시간 기반 보호는 구현이 그것을 지킬 때만 유용하다.RFC 1337은 “TIME-WAIT 암살(TIME-WAIT assassination)”을 기록했다. 오래된 세그먼트가 ACK를 유발하고, 이미 상태를 폐기한 피어가 리셋으로 응답하며, 그 리셋을 받아들여 TIME-WAIT가 조기에 종료될 수 있다는 것이다.

같은 튜플이 즉시 다시 열리면, 오래된 데이터나 확인 응답이 새 수신 윈도우와 겹칠 수 있다. 이 메모는 잘못된 데이터의 수용, 동기화 상실, 연결 실패를 실제로 보였다. 여기서 배울 점은 TCP의 핸드셰이크가 무용하다는 것이 아니다. 여러 보호 계층은 서로 다른 범위를 가진다는 점이다. 핸드셰이크는 오래된 개시 SYN을 거부하고, 시퀀스 검사는 활성 세대를 감시하며, TIME-WAIT은 연속된 세대 사이를 분리한다.

다른 계층이 존재한다는 이유로 하나를 삭제하는 것은 보완적 증거를 중복으로 오해하는 일이다.

새 번호는 인증된 피어가 아니다

원래 사양들에는 이미, 오래된 중복 방식이 스푸핑까지는 막지 못한다는 경고가 있었다. 다음 초기 시퀀스 번호를 예측할 수 있는 호스트는 응답을 보지 않고도 서버가 기대하는 확인 응답을 위조할 수 있다.

RFC 6528은 이 선택을 강화했다. 이는 타이머를 로컬·원격 주소, 포트, 비밀값에 대한 의사난수 함수와 결합한다. 서로 다른 4-튜플은 외부에서 뚜렷한 관계 없이 각자의 시퀀스 공간을 받고, 시간에 따른 진행은 재사용을 피하는 데 도움을 준다.

이 개선은 유한한 주장만을 보호한다. 경로 밖 공격자는 수용 가능한 번호를 맞히기 어려워진다. 그러나 경로상의 관찰자는 교환을 그대로 볼 수 있다. 피어가 누구인지가 문제일 때, 즉 이 TCP 상태가 현재 것인지가 아니라 피어의 신원이 문제일 때는 여전히 암호화 기반의 애플리케이션 또는 트랜스포트 보안이 필요하다.

챌린지 안에 상태를 실어 보내기

핸드셰이크는 자원의 비대칭도 노출한다. 공개 서버는 겉보기 클라이언트가 어떤 증명도 돌려보내기 전에, 첫 SYN을 받자마자 전송 제어 블록을 할당할 수 있다. 공격자는 위조된 SYN을 대량으로 보내 반쯤 열린 큐를 완성되지 않을 상태로 채워 버릴 수 있다.

RFC 4987은 SYN 플러딩이 1996년에 공개적으로 알려져 실무적으로 심각한 문제가 된 과정을 기록했다. 하나의 대응책인 SYN 쿠키는 할당을 지연시킨다. 서버는 자신의 SYN-ACK 시퀀스 번호를 클라이언트 튜플, 클라이언트 번호, 시각, 선택된 파라미터, 비밀값으로부터 구성한다. 유효한 마지막 ACK가 돌아오면, 서버는 연결을 수용하기에 충분한 상태를 재구성한다.

쿠키는 응답자의 번호를 압축된 커밋먼트로 바꾼다. 세 번째 메시지를 증거로 보존하면서 메모리 할당을 그 증거가 도착하는 시점까지 미루는 것이다. 이 절충은 무료가 아니다. 제한된 비트는 옵션 협상을 제약할 수 있고 구현마다 차이도 있다.

따라서 이 역사의 요점은 단순히 “세 개의 패킷이 TCP를 연다”가 아니다. 그것은 증거에 관한 보다 좁은 결정들의 연속이다. 네트워크는 주장을 전달한다. 엔드포인트는 시퀀스 공간을 선택한다. 상호 확인 응답이 그 선택을 공유된 것으로 만든다. 시간은 낡은 의미를 제한한다. 비밀값은 무차별 추측에 저항한다. 지연된 상태는 답 없는 주장의 비용을 봉인한다. 이 어느 것도 전역 권위가 될 필요가 없으며, 어느 것도 자신의 메커니즘이 관찰할 수 있는 것 이상을 증명하지 않는다.

출처와 증거의 한계

이 RFC들은 사양, 명시된 설계 근거, 그리고 선별된 실패 분석을 제공한다. 그러나 모든 TCP 스택에 대한 배포 시점을 하나하나 알려 주지는 않는다. 지역적 선택이 상호 증거를 통해 공유된 것으로 되어 간다는 이 아키텍처적 독해는 그 메커니즘들로부터의 추론이며, RFC들이 사용하는 표현이 아니다.