• network
  • tcp-ip
  • security

IP의 한계와 TCP·UDP, 3-Way Handshake

IP 프로토콜의 한계를 TCP가 어떻게 보완하는지와 TCP 플래그, 3-way handshake, SYN Flooding 대응 방법을 정리한다.

시리즈 · 네트워크5 / 12
  1. OSI 7 Layer와 계층별 역할, ARP
  2. IP 주소: IPv4와 IPv6, NAT, 체크섬
  3. 라우터: 경로 지정, 브로드캐스트 컨트롤, 라우팅과 스위칭
  4. DHCP 동작 방식과 UDP를 사용하는 이유
  5. IP의 한계와 TCP·UDP, 3-Way Handshake
  6. TCP 4-Way Handshake와 TIME_WAIT
  7. DNS 정리: 구조, 질의 방식, 레코드, 이중화와 위임
  8. 로드 밸런서: 구성 방식, 헬스 체크, L4와 L7
  9. HTTP 메서드와 상태 코드: 멱등성, POST와 PUT의 차이
  10. HTTP의 Stateless·Connectionless와 쿠키, 세션
  11. HTTP/1.1, HTTP/2, HTTP/3 비교
  12. 소켓과 포트, 그리고 웹소켓

IP (Internet Protocol)

IP는 지정한 IP 주소로 데이터를 전달하는 프로토콜이다. 데이터는 패킷(Packet)이라는 단위로 쪼개져, 출발지에서 목적지까지 여러 노드를 거쳐 전달된다.

IP 프로토콜의 한계

  • 비연결성: 패킷을 받을 대상의 상태를 알 수 없다. 상대가 수신 불가능한 상태여도 패킷을 그대로 보낸다.
  • 비신뢰성: 중간에 패킷이 사라질 수 있고, 패킷의 순서를 보장하지 않는다.
  • 프로그램 구분 불가: 같은 IP를 쓰는 서버에서 통신하는 애플리케이션이 둘 이상이면 어느 쪽으로 가는 패킷인지 구분할 수 없다.

패킷마다 거쳐 가는 노드 경로가 일정하지 않기 때문에, 아래처럼 보낸 순서와 도착 순서가 달라질 수 있다.

패킷이 서로 다른 경로로 전송되어 도착 순서가 뒤바뀌는 모습

TCP (Transmission Control Protocol)

TCP는 IP 위에서 위 한계를 보완하는 전송 계층 프로토콜이다. 동작은 크게 세 단계로 나뉜다.

  • 연결 생성 (Connection establishment)
  • 자료 전송 (Data transfer)
  • 연결 종료 (Connection termination): 4-Way Handshake에서 따로 다룬다.

TCP 플래그

플래그 의미 설명
SYN 연결 요청 세션을 성립할 때 가장 먼저 보내는 패킷이다. 임의로 정한 초기 시퀀스 번호를 함께 보낸다.
ACK 응답 상대방의 패킷을 받았음을 알린다. 받은 시퀀스 번호에 받은 데이터의 길이를 더한 값을 응답 번호로 보낸다(핸드셰이크에서는 +1). 송신 측은 ACK로 전송 성공 여부를 판단해 재전송하거나 다음 패킷을 보낸다.
FIN 연결 종료 더 이상 전송할 데이터가 없음을 알리고 세션을 종료할 때 사용한다.
RST 연결 재설정 비정상적인 세션 끊기에 해당한다. 보내는 쪽이 현재 연결을 즉시 끊고자 할 때 사용한다.
PSH 밀어 넣기 버퍼가 채워지기를 기다리지 않고 받은 데이터를 즉시 응용 프로그램으로 전달하게 한다. TELNET처럼 빠른 응답이 중요한 대화형 트래픽에 쓰인다.
URG 긴급 데이터 Urgent pointer가 유효함을 나타낸다. 전송하는 데이터 중 다른 데이터보다 먼저 처리해야 할 긴급한 내용이 있을 때 사용한다.

TCP는 ACK를 받을 때까지 데이터를 재전송하는 PAR(Positive Acknowledgement with Re-transmission) 방식으로 신뢰성을 확보한다.

연결 생성: 3-Way Handshake

데이터를 전송하기 전에 연결을 설정하는 과정이다. 양쪽 모두 데이터를 주고받을 준비가 되었음을 보장하고, 실제 전송을 시작하기 전에 서로 상대가 준비되었다는 것을 알 수 있게 한다.

클라이언트와 서버가 SYN, SYN-ACK, ACK를 주고받는 3-way handshake 과정

  1. SYN (클라이언트 → 서버): SYN = 1, ACK = 0으로 설정하고, 초기 시퀀스 번호(ISN)를 무작위 값 A로 정해 보낸다.
  2. SYN-ACK (서버 → 클라이언트): SYN = 1, ACK = 1로 설정한다. 응답 번호는 A + 1이고, 서버도 자신의 ISN을 무작위 값 B로 정해 보낸다.
  3. ACK (클라이언트 → 서버): SYN = 0, ACK = 1로 설정한다. 시퀀스 번호는 서버가 보낸 응답 번호(A + 1), 응답 번호는 B + 1이다.

이 과정을 거쳐 서버와 클라이언트가 논리적으로 연결되므로 IP의 비연결성을 보완할 수 있다. 다만 어디까지나 논리적인 연결이지, 물리적으로 전용 회선이 연결된 상태를 뜻하지는 않는다.

2-Way Handshake를 하지 않는 이유

두 번만 주고받으면 서버는 자신의 응답이 클라이언트에 도착했는지, 즉 연결이 실제로 맺어졌는지 알 수 없다. 다음 상황을 보자.

  1. 클라이언트 → 서버: SYN
  2. 서버 → 클라이언트: ACK (네트워크에서 지연됨)
  3. 클라이언트가 타임아웃되어 SYN을 다시 보낸다.
  4. 서버가 처음에 보낸 ACK가 그제야 도착한다.

2-way라면 서버는 SYN을 받을 때마다 연결이 맺어졌다고 판단하지만, 클라이언트는 어떤 요청에 대한 연결인지 확신할 수 없어 양쪽의 상태가 어긋난다. 마지막 ACK가 있어야 양쪽 모두 상대가 준비되었음을 확인할 수 있다.

두 호스트가 동시에 연결을 시도하면 연결이 가능한가

가능하다. 두 호스트가 서로의 80번 포트로 동시에 연결을 시도하는 경우를 보자. 이때 두 호스트 모두 80번 포트에서 수신 대기하는 서비스가 있어야 한다.

Connection 1: 192.168.1.5 sends SYN to 192.168.1.6 on port 80.
Connection 2: 192.168.1.6 sends SYN to 192.168.1.5 on port 80.

각 수신 서비스는 상대방도 SYN을 보냈는지 알 수 없으므로, SYN-ACK를 보내지 않을 이유가 없다.

Connection 1: 192.168.1.6 responds with SYN-ACK to 192.168.1.5
Connection 2: 192.168.1.5 responds with SYN-ACK to 192.168.1.6

SYN-ACK를 받은 발신 측은 TCP 프로토콜에 따라 ACK로 응답한다.

Connection 1: 192.168.1.5 sends ACK to 192.168.1.6 on port 80.
Connection 2: 192.168.1.6 sends ACK to 192.168.1.5 on port 80.

결과적으로 핸드셰이크가 완료된 두 개의 독립적인 연결이 만들어진다.

  • 두 연결은 서로에 대해 알지 못한다.
  • 둘 중 어떤 연결을 끊을지는 TCP의 관할이 아니라 응용 프로그램이 결정할 일이다.

참고: What happens when 2 hosts simultaneous establish a connection in a 3-way handshake

자료 전송

TCP 세그먼트는 IP 패킷 안에 캡슐화되어 전달된다.

TCP 세그먼트가 IP 패킷 안에 캡슐화된 구조

TCP 세그먼트에는 PORT와 순서 정보가 들어 있다. 순서 정보로 비신뢰성을, PORT로 프로그램 구분 문제를 해결한다.

SYN Flooding

3-way handshake의 half-open 상태를 악용한 DoS 공격이다. 서버는 SYN을 받으면 SYN-ACK를 보내고, 마지막 ACK를 기다리는 동안 연결 정보를 백로그 큐에 보관한다.

  • 공격자는 다량의 SYN 패킷만 보내고 이후 아무런 동작도 하지 않는다.
  • 백로그 큐가 가득 차면 서버는 정상적인 연결 요청을 받지 못한다.

방화벽이 서버 대신 SYN을 먼저 받고, SYN Cookie를 시퀀스 번호에 담은 SYN+ACK를 보내는 방법이다.

방화벽이 SYN Cookie로 클라이언트를 검증한 뒤 클라이언트가 서버와 새로 핸드셰이크하는 과정

  1. SYN이 들어오면 방화벽이 syn_cookie가 포함된 SYN+ACK를 보낸다.
  2. syn_cookie에 맞는 정상적인 ACK가 들어오면 세션을 새로 연다. 일정 시간 동안 정상적인 응답이 없으면 방화벽에서 차단한다.

처음에 방화벽과 맺은 3-way handshake는 없던 셈 치고, 이후의 새로운 3-way handshake를 서버에 연결해 주는 방식이다. 따라서 클라이언트 입장에서는 첫 접속이 실패한 것처럼 보일 수 있지만, 재접속 요청이 순식간에 이루어지므로 사용자가 체감하기는 어렵다.

대응 2: SYN Proxy

방화벽에서 정상적인 3-way handshake가 이루어지면, 방화벽이 그 연결을 서버에게 그대로 재현해 주는 방식이다.

방화벽이 클라이언트와 핸드셰이크를 마친 뒤 서버와의 핸드셰이크를 대신 수행하는 SYN Proxy 과정

  • 3-way handshake가 완료되지 않은 요청은 방화벽에서 차단한다.
  • SYN Proxy도 syn_cookie를 이용해 정상적인 3-way handshake인지 확인한다.
  • 클라이언트와 방화벽 사이에 맺은 핸드셰이크를 방화벽이 서버에 재현해 주므로, SYN Cookie 방식과 달리 클라이언트가 세션을 새로 맺을 필요가 없다.

UDP (User Datagram Protocol)

  • 하얀 도화지에 비유될 정도로 기능이 거의 없다.
  • IP에 PORT 정도만 추가된 형태이다. 연결 과정도, 순서 보장도 없다.

대부분의 통신은 TCP를 사용하지만, HTTP/3는 UDP 기반으로 설계되었다. 이 내용은 HTTP/1.1, HTTP/2, HTTP/3 비교에서 다룬다.

Reference