개발세발보안중
TCP Connection Establishment and Termination 본문
TCP는 연결형 프로토콜 : 종단이 서로 데이터를 송신하기 전에 이들 사이에 연결을 확립
TCP Flag
| 플래그 | 3문자 약어 | 설명 |
| S | SYN | 순서번호의 동기 |
| F | FIN | 송신자는 데이터 송신을 종료 |
| R | RST | 연결의 재설정 |
| P | PSH | 수신 프로세스가 가능한 빨리 데이터를 보낸다 |
| . | 위의 4개의 플래그가 설정된 것이 없다 |
A → B연결을 위해 SYN 송신 (S)
A → B Window size (내가 받을 수 있는 buffer size) <mss, maximum segment size>
A ← B 응답 : SYN + ACK Win size, mss
A → B ACK
A → B FIN
A ← B ACK
A ← B FIN
A → B ACK
연결 확립 프로토콜
1. SYN : 서버의 포트번호, 클라이언트 초기번호(ISN) 지정한 SYN세그먼트를 보냄
2. SYN + ACK : ISN+1 ACK 보냄
3. ACK : 서버로부터 보내 온 SYN에 대하여 서버의 ISN + 1 ACK로 확인응답을 보냄
→ three-way handshake
3단계 연결 절차
1) 클라이언트는 SYN 플래그만 설정되어있는 첫 번째 세그먼트인 SYN 세그먼트를 전송
* 세그먼트는 순서번호들의 동기화를 위한 것
(이때, SYN 세그먼트는 데이터를 운반할 수 없으나 순서번호 1개를 소비)
2) 서버는 2개의 플래그 비트가 설정된 두 번째 세그먼트인 SYN+ACK 세그먼트를 전송
(SYN+ACK 세그먼트는 데이터를 운반할 수 없으며 순서번호 1개 소비)
3) 클라이언트가 세 번째 세그먼트를 전송 (ACK 세그먼트)
ACK 플래그와 확인응답 번호 필드를 사용 (두 번째 세그먼트를 수신한 것에 대한 확인응답)
(데이터를 운반하지 않는다면 ACK 세그먼트는 순서번호를 소비하지 않음)
출처: https://haloworld.tistory.com/15 [Halo World:티스토리] 좀 더 쉬운 이해를 위해 가져옴
일반적인 연결 종료 프로토콜
1. 능동 폐쇄 클라이언트가 close를 호출해 해당 연결로 더 이상 보낼 데이터가 없다고 선언하면, TCP는 close 호출 전에 클라이언트에게 처리 요청 받은 보낼 데이터를 모두 보낸 뒤 FIN을 송신함
2. 수동 폐쇄 서버 TCP는 앞의 데이터를 모두 받고 FIN을 수신하면 응용에 EOF (End of File) 을 전달하여 연결이 닫힘을 알리고 클라이언트 TCP에 FIN 을 보냄
3. active close 서버는 read함수에서 EOF가 리턴된 걸 확인하면 보통 해당 연결에 대한 close를 호출하도록 프로그램 되어있다.
4. 클라이언트는 FIN을 수신하면 FIN을 담은 세그먼트 순서번호에 1을 더한 ACK를 보낸다

연결 확립의 타임아웃
- 연결 확립할 수 없는 예: 서버 호스트의 다운
최대 세그먼트 크기
MSS(Maximum Segment Size) : TCP가 상대편에 한번에 보낼 수 있는 데이터의 최대 크기, 수신할 수 있는 segment size 명시
- 연결이 확립될 때 (SYN) 각 종단은 MSS를 통지 (TCP 옵션)
MSS = MTU - IP헤더 - TCP 헤더 ex) 이더넷 : 1460바이트 (1500-20-20)
Default MSS 설정: 각 종단은 받기를 원하는 MSS를 알리는 option을 갖는다
*상대편에서 MSS를 통지하지 않으면 MSS는 536 바이트로 설정
절반 폐쇄
절반 폐쇄 (half-close) : TCP 연결의 한 쪽 종단이 다른 쪽 종단으로부터 데이터를 전송 받고 있는 상태에서도 데이터의 출력을 종료할 수 있는 기능
- BSD Sockets API는 응용이 close를 대신 shutdown을 호출(두 번째 인자 howto-SHUT_WD)하여 절반 폐쇄함
> 절반 폐쇄가 있음에도 많은 응용은 연결 종료 시 close를 이용하여 양방향 폐쇄를 수행
ex) 서버가 EOF를 받았음에도 1) 보낼 데이터가 남아있고, 2) 응용이 shutdown으로 절반 닫기 했기 때문에 게속 데이터를 수신하는 것이 가능함 (만약 클라이언트가 close했는데 서버가 write하면 데이터 전달 실패됨)
- TCP에서 데이터를 받고 있는 도중에 한쪽이 데이터 전송을 중단하는 것 (대부분 클라이언트에서 중단)
- 클라이언트는 FIN 세그먼트를 전송함으로써 연결을 절반 폐쇄하고, 서버는 ACK 세그먼트를 송신함으로써 이를 받아들임
-> 이 경우 클라이언트에서 서버로의 데이터 전송을 멈추지만, 서버는 여전히 데이터 송신 가능
-> 서버가 데이터를 다 전송하고 FIN 세그먼트를 보낼 경우, 클라이언트는 ACK 세그먼트 전송 가능
출처: https://haloworld.tistory.com/15 [Halo World:티스토리]

이 천이도는 Server와 Client의 상태변화를 하나의 그림으로 나타낸 것이다.
State transition diagram
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=airbag1&logNo=80037429661
TCP의 상태 천이도 분석
TCP의 상태 천이도 분석 연결 설정, 연결종료, 그리고 데이터 전송 기간 동안 발생하는 여러 가지의 이...
blog.naver.com
재설정 세그먼트
재설정은 참조 연결에 대해서 바르지 않은 세그먼트가 도착할 때 발생함
- 참조 연결(reference connection): 4-tuple이 명시된 연결, 즉 FRC 793에서의 socket
재설정 세그먼트가 사용되는 예: 존재하지 않는 포트에 대한 연결 요청
연결 요청이 목적지에 도청했지만, 목적지 포트 상에 listen중인 프로세스가 없는 경우
- 연결 중단 (Aborting a Connection)
정규해제(ordinary release): 상대편에 FIN신호를 보내서 연결을 종료(terminate)한 상황
FIN은 큐에 대기한 데이터를 모두 전송한 후에야 전송되므로, 데이터에 대한 손실이 없음
중단해제(abortive release): FIN대신에 재설정(RST)을 전송하여 연결을 중단(abort)한 상황
- 연결 중단을 할 경우에 응용이 얻는 장점
- 대기 중인 (queued) 데이터를 바로 버리고 즉시 재설정 신호(RST)를 전송해 연결을 재설정 가능
- RST의 수신측 TCP는 응용에게 'RST 송신측이 연결을 중단했음'을 알릴 수 있음
* 따라서, API는 응용이 연결 중단을 할 수 있는 방법을 제공해야 함
- 절반 개방 연결
절반 개방 (half-open)
- 호스트 A가 호스트 B에게 세그먼트를 따로 보내지 않고 연결을 종료 또는 중단 (e.g.,호스트 A가 고장 또는 재부팅)
- 절반만 개방된 상태이더라도, B가 데이터 전송을 시도하지 않으면 B는 고장을 알 수 없음
*때문에, 절반 개방된 연결로 B가 세그먼트를 보내는 경우, A의 TCP는 RST로 응답해야 함
TWA, TIME_WAIT Assassination
server가 오래전에 보낸 패킷이 늦게 도착하고 이를 응답하는 바람에 Server가 RST를 보내서 Client의 TIME_WAIT를 의도치 않게 꺼버리는 문제
동시 개방
- TCP의 상태 천이 다이어그램을 보면,호스트 A와 호스트 B가 서로 간에 각각 SYN을 보내서 연결을 만들려고 할 수 있음
- 이 때 TCP 표준은 두 개의 연결을 만드는게 아니라 하나의 연결만이 이루어지도록 설계됨
- 보통 동시 개방은 이론상의 시나리오였으나, 각각 Network Address Translation을 거쳐야 글로벌 인터넷을 사용 가능한 두 호스트가 상호간에 outbound TCP 연결 (즉, peer-to-peer 연결)을 만들 필요가 있을 때 사용되며, 이를 TCP Hole Punching이라고 부름
동시 폐쇄
- 양쪽 종단으로부터 능동적 폐쇄를 수행할 수 있음
- 동시 폐쇄는 일반적인 폐쇄와 같은 수의 세그먼트 교환
TCP 서버 설계
TCP 서버는 병행성(concurrent;동시성)을 갖도록 설계함
> 서버는 새로운 연결 요청이 도착하면 서버는 그 연결을 받아들이고 새로운 클라이언트를 처리하기 위해 새로운 프로세스 또는 스레드를 가동함
- 외부 IP 주소의 제한
[로컬 주소] [외부 주소]
수신 연결 큐 (Incoming Connection Queue)
- 병행 서버는 각 클라이언트를 다루기 위해 새 프로세스를 만들 수 있지만, listen을 위한 서버는 accept 함수를 사용해 한 개의 연결 요청만을 처리할 수 있음
- 그렇다면, 여러 개의 연결 요청이 동시에 들어오면? ->
- 더군다나, 연결 설립이 되지 않는 (three-way handshake이 제대로 끝나지 않은)연결 요청으로 공격을 받고 있다면?
SYN flooding DoS attack
이런 문제를 TCP는 어떻게 다루는가?
> 이러한 연결들은 (1)SYN은 받았지만 아직 연결 설립이 되지 않은 연결, (2) hand shaking이 끝났지만 listen을 위한 서버가 아직 accept하지 못한 연결 중 하나
- 운영체제에 포함된 TCP 구현은 각 상황을 처리하기 위한 연결 큐를 각각 가지고 있음
- 응용은 제한된 문맥에서 이 두 개의 큐의 크기를 조절할 수 있음 (BSD Sockets API는 전통적으로 두 큐의 합 크기를 설정하는 옵션을 제공했지만, 최신 Linux 커널은 해당 옵션을 사용하면 (2)번 큐의 크기를 정함)
- 리눅스에서 수신 연결 큐에 관한 규칙
~~~
- 결국, BSD Sockets API에서, 응용이 연결 도착을 알게 되었을 때에는 이미 TCP의 three-way handshaking이 끝나있는 상태임에 주의할 것
* 한편, TCP 클랑이언트의 connnect는 서버로 SYN+ACK 를 받으면 리턴되므로, 서버가 연결 소켓을 가지게 될 때에는 이미 클라이언트가 데이터를 보냈을 수 있음
'Network Security and IDS' 카테고리의 다른 글
| 방화벽 (0) | 2022.11.22 |
|---|---|
| Sniffing and Spoofing (0) | 2022.10.22 |
| TCP (0) | 2022.09.27 |
| UDP (0) | 2022.09.27 |
| ARP(Address Resolution Protocol) (0) | 2022.09.27 |