블로그 이전했습니다. https://jeongzero.oopy.io/
연결지향형 전송계층 프로토콜 : TCP
본문 바로가기
컴퓨터 관련 과목/Network

연결지향형 전송계층 프로토콜 : TCP

728x90

3-way handshaking 이란?


TCP는 애플리케이션 프로세서가 데이터를 다른 프로세스에게 보내기 전에, 두 프로세스가 서로 핸드셰이크를 먼저 해야 하므로 연결지향형이다. 즉 데이터 전송을 하기 전에 연결 설정을 해야 하는 파라미터들을 보내야 한다.  또한 TCP는 전이중 서비스를 제공한다. 전이중 서비스란 전화를 생각하면 된다. 그냥 동시에 서로 말하는게 가능 하는 것처럼 A와 B 사이에 TCP 연결이 되어있다면 A에서 B로 보내는 동시에 B에서 A로 데이터 전송이 가능하다.


앞서 말한 연결 설정이란 3가지 주고 받는 메시지를 이용하기 때문에 3-way 핸드셰이킹이라고 부른다. 


1. 클라이언트는 TCP 연결을 하고자 하는 서버에게 SYN 비트(TCP 헤더의 Flag 필드의 값임)와 최초의 순서번호를 보낸다(x)


2. SYN 세그먼트를 포함하는 IP 데이터그램이 서버에 도착했을 때, 서버는 데이터그램으로부터 SYN 세그먼트를 뽑아낸다. 그리고 연결에 TCP 버퍼와 변수들을 할당한다. 또한 클라이언트 TCP로 연결 승인 세그먼트를 송신한다. 여기서 보내는 송신 세그먼트는 3가지를 포함하고 있다. 첫째로 SYN 비트는 1로 세팅을 하고 두번째로 요청에 대한 확인응답인 ACK 비트를 1로 세팅한다. 그리고 마지막으로 서버의 최초 순서번호를 선택하고 TCP 세그먼트 헤더의 순서번호 필드에 이 값을 넣는다.  이 말인 즉슨 서버가 "나는 너의 최초 순서번호인 x를 가지고 연결을 시작하기 위해서 당신의 SYN 패킷을 수신 잘했고 이 연결 설정에 동의해. 나의 최초 순서번호는 Y야." 라고 말하고 있는 것이다.


3. 클라이언트는 이 SYN, ACK 패킷을 수신하면 연결을 위한 버퍼와 변수들을 할당한다음 서버로 오켕이 그럼 연결설정 된거다!! 라는 확인차 패킷을 보내는데 여기에서는 연결설정이 됬기 때문에 SYN 비트는 0으로 설정하고 ACK 비트에 Y+1 값을 넣는다. 


3-way 핸드셰이크는 이러한 과정으로 진행되고 이 이후부터 실질적인 데이터의 전송이 이루어진다.(1,2,번에서는 페이로드에 내용이 안들어가 있으며 3번째 단계부터는 페이로드에 데이터가 운반 될 수 도 있음) 근데 여기서 알아두면 좋은게 있다. SYN 플러드 공격이라는 것이다.




SYN 플러드 공격이란?


여태까지 서버가 수신된 SYN에 대한 응답으로 연결 변수와 버퍼를 할당하고 초기화하는 TCP 3-way 핸드셰이킹을 설명했다. 클라이언트가 SYN 세그먼트를 보내면 서버는 해당 요청에 대한 응답으로 서버에 시스템 자원을 할당하고 클라이언트에 SYN,ACK 세그먼트를 보낸다. 그리고나서 ACK 세그먼트를 기다린다. 악의적인 사용자는 이를 이용하여 핸드셰이크 세 번째 단계를 완료하지 않은 상태에서 존나게 많은 TCP SYN 세그먼트를 보낸다. 


이 TCP SYN 세그먼트의 대홍수로 서버의 연결 자원이 반쪽만 연결이 할당되어(할당되기만 하고 전혀 사용되지 않은 상태) 결국 서버의 백로그 큐가 꽉차서 더이상의 요청을 받을 수 없게 된다. 이를 흔히 말하는 DOS 공격이라고 한다.


다행이도 현재 대부분의 주요 운영체제에는 SYN 쿠키라고 불리는 효과적인 방어책을 가지고 있기 때문에 걱정안해 될거같다. SYN 쿠키는 다음과 같은 동작을 한다.


서버가 SYN 세그먼트를 받을 때, 그 세그먼트가 정당한 사용자로부터 온 것인지 SYN 플러드 공격의 한 부분인지 알 수 없다. 그래서 서버는 이 SYN에 대해서 반만 열린 TCP 연결을 만들지 않고, 대신 서버는 오직 자신만 아는 비밀번호 뿐만 아니라 SYN 세그먼트의 출발지와 목적지 IP 주소들과 포트번호들의 복잡한 해쉬 함수로 초기 TCP 순서번호를 만든다. 이 초기 순서번호를 소위 쿠키라고 부른다. 


그러고 나서 서버는 이 특별한 초기 순서번호를 가진 SYN, ACK 패킷을 보낸다. 중요한 것은 서버가 SYN에 관련된 쿠키나 어떤 다른 상태 정보를 기억하지 않는다는 것이다.


정상적인 클라이언트는 ACK 세그먼트를 돌려준다. 이 ACK를 ㄹ받은 서버는 ACK가 이전에 보낸 일부 SYN에 관한 것인지 확인해야 한다. 그러나 서버가 SYN 세그먼트에 관한 메모리가 없다면 이를 어떻게 하는 것일까? 이는 쿠키로 확인한다. 정상적인 ACK를 보면 확인응답 필드에 있는 값은 SYN,ACK에 있는 순서번호에 1을 더한 것과 같다. 


그렇다면 서버는 SYN,ACK 세그먼트에 있는 IP 주소와 포트 번호 그리고 비밀번호를 사용해서 동일한 해시 함수를 실핼할 것이다. 만약 함수의 결과에 1을 더한 것이 클라이언트에 SYN,ACK에 있는 확인응답 번호(쿠키)와 같다면, 서버는 ACK가 초기 SYN 세그먼트에 관련된 것이고, 따라서 올바른 것이라고 결론 짓는다. 그 이후 서버는 소켓을 가지고 완전하게 열린 연결을 만든다. 


반면에, 클라이언트가 ACK 세그먼트를 돌려받지 않으면, 서버가 처음의 가짜 SYN에 대하여 어떤 자원도 할당하지 않았으므로, 처음 SYN은 서버에 해를 끼치지 못한다.





4-way handshaking이란?

3-way 핸드셰이킹이 완료되면 그때부터 실질적인 데이터 전송이 이루어진다고 했다. 그렇다면 데이터 송수신이 완료되면 당연히 종료를 해야지 않겠는가? 종료를 하지 않으면 송수신 과정에 할당했던 자원들이 계속 사용되지 않은채 자리를 차지하게 되고 이는 자원 낭비로 연결된다. 따라서 모든 자원을 회수하고 연결을 종료하는 과정을 항상 거쳐야 하는데 이를 4-way 핸드셰이킹이라고 한다.


먼저 클라이언트가 연결 종료를 결정한다고 가정하자. 클라이언트 애플리케이션 프로세스는 종료 명령을 내리고, 이것은 클라이언트 TCP가 서버 프로세스에게 특별한 TCP 세그먼트인 FIN을 보내도록 한다.



이 특별한 세그먼트는 1로 설정된 FIN 비트라 불리는 플래그 비트를 세그먼트 헤더에 포함하고 있다. 서버가 이 세그먼트를 수신하면, 서버는 클라이언트에게 확인 세그먼트를 보낸다. 위 그림에서 보면 처음에 클라이언트가 FIN 비트를 1로 해서 순서번호와 함께 보낸다. 서버가 이를 수신하면 그에 대한 확인 응답인 ACK 비트를 1로 해서 보내고 순서번호에 +1 해서 ACKnum으로 보낸다. 여기서 바로 클라이언트가 응답을 하는게 아니라 종료할 준비가 끝나면 서버는 바로 이제 진짜 종료하자! 라는 의미의 FIN 비트와 서버 순서번호인 y를 보낸다.


그럼 마지막으로 클라이언트는 서버로부터 FIN 비트를 받으면 오케이 알았어~~ 라는 확인차 메시지인 ACK 비트와 서버의 순서번호인 y에 +1해서 다시 서버한테 보낸다. 최종적으로 서버가 다시 이 ACK 비트를 받는순간에 정말 연결 종료가 이루어진다.





위 그림은 TCP 헤더의 포맷인데 저기 세로로 쎠져 있는 부분이 TCP 헤더의 FLAG 부분이다. SYN,ACK,FIN 이것들은 앞서 말한 부분에서 사용되고 URG는 긴급데이터의 의미로 긴급하게 다른것보다 먼져 보내야하는 패킷에게 설정하는 플래그이다. RST는 비정상적인 종료시에 사용되는 플래그 비트이다.  RST 패킷을 보내는 곳이 현재 접속하고 있는 곳과 즉시 연결을 끊고자 할 때 사용한다. 


마지막으로 PSH는 TELNET과 같은 상호작용이 중요한 프로토콜의 경우 빠른 응답이 중요하다. TCP는 원래 할당한 TCP 버퍼가 꽉채워졌을때 애플리케이션 계층으로 전송이 되는데 PSH 패킷은 버퍼가 다 채워지지 않아도 바로 애플리케이션 계층으로 전송이 가능하다.





728x90

'컴퓨터 관련 과목 > Network' 카테고리의 다른 글

라우터 내부에는 무엇이 있을까?  (0) 2019.01.06
TCP 혼잡제어  (0) 2019.01.05
비연결형 전송계층 프로토콜 : UDP  (0) 2019.01.05
DNS란?  (1) 2019.01.05
쿠키란?(먹는거 아님)  (0) 2019.01.03