URL에 접근 시 일어나는 Handshake
URL입력 후 일어나는 일들에 대한 포스팅의 2탄입니다.
이전 이야기에서 TCP 통신을 진행 할 때 일어나는 TCP-Handshake와 SSL-Handshake에 대해서 언급하며 추후에 포스팅을 하겠다는 말씀을 드렸습니다. 이번에 그 Handshake에 대해서 공부해보겠습니다.
Handshake란?
영어로 Handshake의 뜻은 “악수”입니다. 클라이언트와 서버가 서로에게 특정한 통신하기 전 서로를 확인하는 절차라고 말씀드릴 수 있습니다. TCP-Handshake는 TCP통신 전 서로를 확인하는 작업이며, SSL-Handshake의 경우에는 클라이언트의 보안을 위해 서로를 확인하는 작업입니다.
TCP-Handshake
TCP-Handshake는 크게 2가지로 나눌 수 있습니다. 3-Way-Handshake와 4-Way-Handshake입니다.
먼저 TCP 헤더에 대해서 간단히 훑어보겠습니다.
- 송신자 포트번호와 수신자 포트번호가 입력됩니다.
- Sequence Number는 현재 세그먼트의 시작번호(byte 단위로)로써 이 값을 이용하여 신뢰성과 흐름제어를 보장합니다.
- Acknowledgment Number는 요청에 대한 응답 시 다음 요청에서 받고 싶은 세그먼트의 시작번호를 나타냅니다. 예를 들면 Ack Number가 100이라면 Sequence Number 100의 세그먼트를 받고자 하는 것입니다.
- Offset은 실제 데이터가 어디서부터 저장되어있는지 알려주는 수 입니다. 바이트 단위로 적혀있기 때문에 4를 곱하면 현재 TCP 헤더의 전체 크기가 나옵니다. - 추가적으로 공부한 내용으로는 이후에 나오는 Option의 크기가 가변적이기 때문에 사용한다고 합니다.
- Reverse는 미래를 위해 남겨놓은 비트로 0으로 3비트가 채워져 있습니다.
- Flag는 현재 세그먼트가 어떤 속성을 갖는지 알려주는 위치 입니다. Handshake에 사용되는 Flag는 SYN(TCP 연결 시 시퀸스 번호와 동기화 Flag),ACK(Acknowledgment Number가 있음을 알리는 Flag),FIN(종료)입니다.
- Window Size는 한번에 보낼 수 있는 데이터의 양으로 혼잡제어에서 사용하는 Sliding과 관련이 있는 것 같습니다.
- CheckSum은 오류 감지를 사용하는 것으로 알고 있습니다.
- Urgent Pointer는 긴급 포인터로써 우선적으로 처리 할 데이터의 여부를 나타내줍니다.
- Option으로 여러가지가 추가되어 전송 될 수 있다고 합니다.
아직 이 부분은 잘 모르겠습니다만, 공부해보겠습니다.
TCP 과정을 거치면서 여기 TCP 헤더에 있는 Flag부분에 비트 단위로 해당 패킷이 어떤 용도로 사용되는지 알 수 있습니다. 먼저 요청을 나타내는 SYN과 응답을 나타내는 ACK 그리고 연결을 끝내는 FIN만 알아둡시다.
본격적으로 Handshake에 대해 공부해보겠습니다.
첫 번째로 3-Way-Handshake는 클라이언트와 서버가 통신을 하기 전 서로를 확인하는 절차입니다. TCP프로토콜의 특성 상 신뢰성있고 연결형 통신을 지원하기 때문에 통신을 하기 전 클라이언트와 서버가 연결되는 루트를 찾아야 합니다.
가장 먼저 클라이언트 측에서 SYN(요청) Flag를 가진 패킷을 서버 측에 전송합니다. 서버에서는 해당 패킷을 받게되면 ACK(응답)/SYN(요청) Flag를 동시에 가진 패킷을 다시 클라이언트에게 전송합니다. 그리고 다시 클라이언트 측에서 ACK(응답)패킷을 서버측에 전송하면서 Handshake가 마무리 됩니다.
해당 과정이 끝나면 클라이언트와 서버는 서로를 확인하게 되었으며, 서버는 클라이언트와 연결이 된 상태가 됩니다. 서버측에서 클라이언트에 대한 정보를 처리할 수 있게 되는 것 입니다.
이 후 통신을 진행하게 되면 Handshake를 통해 알게 된 루트(라우트)를 사용해서 통신을 진행하는 것으로 알고 있습니다. 해당 루트는 명확하게 클라이언트와 서버가 지나온 루트이기 때문에 확실하게 서로를 연결하고 있음을 알기 때문입니다.
두 번째로 4-Way-Handshake는 클라이언트와 서버가 통신을 끝낸 후 서로의 연결을 해제하는 절차입니다. 통신이 끝났을 때 클라이언트와 서버는 서로 통신이 끝났음을 알려야 합니다. 이유로는 상시 통신이 진행중이지 않고, 특정한 이벤트가 발생했을 때 통신이 발생하기 때문입니다. 예를 들면 우리가 페이지에서 가만히 있으면 아무런 통신도 발생하지 않습니다. 페이지를 전환하거나(리소스를 받거나) REST API 등을 사용할 때만 통신하면 됩니다.
가장 먼저 클라이언트 측에서 FIN Flag를 가진 패킷을 서버 측에 전송합니다. 서버에서는 해당 패킷을 받게되면 ACK Flag를 클라이언트 측에 전송합니다.
이 후 잠시 서버는 시간을 기다리며 아직 클라이언트에게 보내지 못한 리소스가 있다면 모두 전송해줍니다. 이 시간을 갖기 위해서 서버는 조금 늦게 클라이언트에게 다시 FIN Flag를 가진 패킷을 전송합니다.
마지막으로 클라이언트가 FIN Flag에 대한 ACK Flag를 전송해주면 4-Way-Handshake가 완료됩니다. 이것으로 서버와 클라이언트를 연결하는 TCP 연결이 해제됩니다.
SSL-Handshake
SSL-Handshake는 HTTPS에서 Secure(보안)을 위해 진행되는 인증 과정입니다. 정확히 말하면 서버와 클라이언트 간의 통신을 위한 대칭키 기반 암호화를 진행하기 위해 대칭키를 안전하게 교환하기 위해 공개키방식을 이용하는 방법입니다.
이 개념을 익히기 전에 CA(인증 기관)에 대한 이해를 먼저 해보겠습니다.
CA는 디지털 인증서를 발급해주는 기관입니다. 여기서 디지털 인증서라는 것은 공개키 인증서로써 공개키 방식으로 암호화 혹은 복호화를 위한 키로 쓰이는 인증서입니다.
제가 이해 한 내용을 그림으로 그려보겠습니다.
가장 처음에 클라이언트는 클라이언트의 버전(아마 브라우저의 버전으로 추정됩니다)/ 암호 알고리즘의 목록/ 사용 가능한 압축 방식 목록을 “Client Hello” 메세지로 서버측에 보냅니다.
서버측은 “Client Hello” 메세지에서 암호 알고리즘과 압축 방식을 선택 합니다. 그 뒤 CA(인증기관)에게 인증받은 서명을 받은 인증서를 함께 담아 “Server Hello” 메세지로 보냅니다. 이때 인증서는 서버측이 가지고 있는 공개키입니다.
클라이언트 측에서는 “Server Hello” 메세지에서 얻은 공개키로 유효한 인증서인지 검증을 해야합니다. 기본적으로 브라우저는 신뢰할 수 있는 CA의 목록과 공개키를 가지고 있기 때문에 일일이 모든 CA를 찾지 않아도 검증을 시작할 수 있지만 목록에 없는 공개키 일 수 있습니다. 이때는 네트워크를 통해 관련 CA의 정보와 공개키를 얻어내고 검증을 시작합니다.
해당 인증서가 올바르지 않은 인증서라면 인증서가 없음을 알리고, 있다면 의사 난수를 만들어서 해당 공개키로 암호화 한 뒤 서버에게 전달 합니다. 여기서 의사 난수는 이후에 클라이언트와 서버가 통신을 할 때 사용 할 대칭키가 됩니다.
서버측은 공개키와 함께 복호화 할 수 있는 개인키를 가지고 있기 때문에 클라이언트가 보낸 암호문을 복호화하여 의사 난수를 알 수 있습니다.
이로써 클라이언트는 자신이 생성했기에 안전한 대칭키를 얻었고, 개인키만이 복호화 할 수 있는 공개키로 암호화하여 서버에게 보냈기에 노출되지 않게 되었습니다.
이 후 정상적인 통신이 진행 되었는지 교환 이력을 대칭키로 암호화하여 주고 받음으로써 통신을 마무리합니다.
앞으로의 통신은 해당 대칭키를 이용하여 통신하면 공개키 방식보다 빠른 통신이 가능해집니다.
참고
https://evan-moon.github.io/2019/11/10/header-of-tcp/