네트워크를 공부했던 사람이라면 TCP 의 접속 과정인 '3-way handshake', '4-way handshake' 등의 용어를 들어봤을 것이다.
CS 스터디를 하던 중 나는 이번에 'SSL/TLS handshake'를 주제로 발표를 맡았다. 처음 들어봤기 때문에 생소했지만 꽤나 흥미로운 내용들이 많았다. 가령 HTTPS 에 접속하는 과정이 어떻게 이루어지는지 등 말이다. 공부하기 전 개념과 과정을 살펴보니 웹 개발자로서 꼭 필요한 내용이라고 생각이 된다.
우리가 단순히 인터넷에 접속하기까지 수 많은 패킷이 오가며 암호화 통신을 한다.
실제로 우리는 기존 인터넷 방식인 'http' 에 보안을 결합한 'https' 를 자주 접하고, 이 때 암호화 통신이 적용 된다.
SSL/TLS handshake 를 이해하기 전에 SSL/TLS 가 무엇인지 모른다면 아래 글을 참고하면 되겠다.
https://jnsodevelop.tistory.com/68
[Network] SSL/TLS 란?
1. 개념 1) SSL (Secure Sockets Layer) SSL은 '보안 소켓 계층' 이라고 불리는 암호화 기반 인터넷 프로토콜이다. 1995년 Netscape 사에서 처음 개발되었으며, 인터넷 통신에서 개인 정보 보호, 인증, 데이터
jnsodevelop.tistory.com
1️⃣ TLS handshake 개념
1. SSL/TLS handshake
SSL (Secure Sockets Layer) 이 발전하여 TLS (Transport Layer Security) 가 되었다. SSL 은 3.0 버전을 최종으로 더이상 나오지 않으며, 현재는 대부분 TLS를 사용하기 때문에 이제부터 TLS handshake 라고 하겠다.
'Handshake'란 말 그대로 악수를 뜻한다. 네트워크에서 이는 클라이언트와 서버간의 통신을 의미하며, 연결적 요소를 가진다.
handshake 를 사용하는 또 다른 용어로는 '3-way handshake', '4-way handshake'가 있다. 이 둘은 클라이언트와 서버가 연결되는 과정이다. 이와 관련된 부분은 다른 글에서 보다 자세히 다루도록 하겠다.
그렇다면 TLS handshake 는 무엇일까? 바로 통신을 하는 클라이언트와 서버가 서로 암호화 통신을 시작할 수 있도록 신분을 확인하고 필요한 정보를 주고 받는 과정을 말한다. TLS handshake 는 클라이언트가 HTTPS를 통해 처음 웹 사이트의 원본 서버를 쿼리하기 시작할 때마다 발생한다. 또한 다른 통신이 API 호출 및 HTTPS를 통한 DNS 쿼리를 포함하는 HTTPS를 사용할 때에도 매번 발생한다.
눈치가 빠른 사람이라면 알아챘을 것이다. 위에서 '3-way handshake' 또는 '4-way handshake'를 통해 클라이언트와 서버가 연결된다고 했다. 이후 HTTPS에 접속한다면 TLS handshake 과정을 통해 암호화된 통신을 시작할 수 있게 된다. 즉, TCP handshake를 통해 TCP 연결이 된 이후에 TLS handshake가 진행된다.
2. SSL 인증서
클라이언트와 서버간의 통신을 제 3자가 보증화 해주는 전자화된 문서이다. 이는 데이터의 기밀성과 무결성, 서버의 신뢰성을 보장한다.
SSL 인증서는 클라이언트가 접속한 서버가 신뢰할 수 있는 서버인지를 판단한다. 또한 통신에 사용될 공개키를 클라이언트에게 전달한다.
인증서엔 서비스의 정보(CA), 서버측 공개키를 담고 있다.
3. CA (Certificate Authority)
네트워크 통신을 할 때 SSL 인증서를 기반으로 클라이언트가 접속한 서버가 의도에 맞는 서버인지 확인한다. 이러한 일을 하는 CA는 디지털 인증서 발급 엔티티로서, 공인된 회사를 뜻한다. CA 리스트는 클라이언트가 갖고 있고, 해당 CA들의 공개키들을 갖고 있다.
인증서를 통해 서버의 신뢰성을 판단하는 과정은 아래와 같다.
- 서버가 SSL 인증서를 제공하며, 인증서에는 서비스 정보와 서버측 공개키를 담고 있다.
- 클라이언트는 해당 인증서를 발급한 CA가 자신의 CA 리스트에 존재하는지 확인한다.
- 만약 리스트에 존재한다면 해당 CA의 공개키를 통해 인증서를 복호화한다. 복호화된다면 CA의 비공개키에 의해 암호화되었다는 것을 알 수 있으므로 서버의 신뢰성을 높일 수 있다.
2️⃣ TLS handshake 과정
1. TLS 1.2
1. TCP Connection
위 그림은 TLS 1.2에서 handshake 과정을 나타낸 그림이다. 앞서 TLS handshake 는 TCP 연결 이후에 진행된다고 하였다.
따라서 파란색인 부분은 3-way handshake로, 클라이언트와 서버가 연결하기 위한 과정이다.
2. Client Hello
클라이언트가 서버에 해당 패킷을 전송하면서 handshake를 시작한다. 해당 메시지엔 클라이언트가 지원하는 TLS 버전, 해당 버전에서 지원되는 암호화 방식들(Chipher suites), '클라이언트 무작위'라고 불리는 무작위 바이트 문자열, 세션 ID, SNI 등을 포함한다.
3. Server Hello
클라이언트에게 받은 Client Hello 패킷에 대한 응답이다. 서버는 클라이언트가 지원하는 암호화 방식들 중 선택된 방식, '서버 무작위'라고 불리는 무작위 바이트 문자열을 포함한 메시지를 클라이언트에게 전송한다. 또 세션 ID를 통해 재연결 세션인지, 새로운 세션인지 확인한다.
4. Certificate
서버가 자신의 SSL 인증서를 클라이언트에게 전송한다. 인증서는 세션키로 암호화한 패킷으로 전송되며, 인증서 내부에는 서버가 갖고 있는 공개 키가 들어있다. 이후 클라이언트는 서버가 보낸 CA의 개인 키로 암호화된 인증서를 CA의 공개 키를 사용하여 복호화한다. 이를 통해 신뢰할 수 있는 웹사이트인지 판단할 수 있다.
5. Server Key Exchange / Server Hello Done
서버 공개 키가 포함된 패킷을 클라이언트에게 전송한다. 만약 SSL 인증서 내부에 공개 키가 존재하면 Server Key Exchange 과정은 생략된다. 클라이언트는 CA의 공개 키를 통해 인증서를 복호화 한 후 서버의 공개 키를 알 수 있다. 이후 서버의 동작이 끝났음을 전달한다.
6. Client Key Exchange
클라이언트는 '클라이언트 무작위'와 '서버 무작위'를 조합하여 대칭 키를 생성한다. 이를 SSL 인증서 내부에서 추출한 서버의 공개 키를 이용해 암호화한 뒤 서버에 전달한다. 여기서 사용된 키 교환 알고리즘에 따라 세션 키를 생성하는 과정이 다르다. 즉, 키 교환 알고리즘 방식을 통해 클라이언트 공개 키 + 서버 비공개 키 -> 클라이언트 비공개 키 + 서버 공개키 -> 세션키 의 과정을 거친다. (동일 개념)
7. Change Cipher Spec / Finished
세션 키를 대칭키로 사용할 것을 정의하여 서버가 클라이언트에게 전송한다. Change Cipher Spec 패킷은 클라이언트와 서버가 서로에게 보내는 패킷으로, 정보 교환을 마친 뒤 통신할 준비가 되었음을 알려준다. 이후 Finished 패킷을 보내 TLS handshake를 종료한다.
8. Application Data
클라이언트와 서버가 서로 TLS 를 통해 암호화 통신을 하는 데이터 패킷이다.
2. TLS 1.3
1. TCP Connection
위 그림은 TLS 1.3에서 handshake 과정을 나타낸 그림이다. 이 과정은 TLS 1.2에서와 같이 동일하게 진행된다.
역시 클라이언트와 서버가 연결하기 위한 과정이다.
2. Client Hello
클라이언트가 서버에 해당 패킷을 전송하면서 handshake를 시작한다. TLS 1.2와 마찬가지로 클라이언트가 지원하는 TLS 버전, 해당 버전에서 지원되는 암호화 방식들(Chipher suites), 인증/해쉬 알고리즘, 세션 ID 등을 전송한다. 또한 서버가 선택할 가능성이 큰 프로토콜을 추측하여 특정 키 프로토콜에 대한 키 공유를 전송한다.
3. Server Hello / Change Cipher Spec (Server)
서버는 클라이언트가 지원하는 암호화 방식들 중 선택된 방식, 서버 비공개 키 등을 포함한 패킷을 클라이언트에게 전송한다. 세션 ID를 통해 재연결 세션인지, 새로운 세션인지 확인한다. 또한 세션키를 생성한 뒤, SSL 인증서를 세션키로 암호화한 패킷을 바꿔 클라이언트에게 전송한다.
4. Change Cipher Spec (Client)
클라이언트는 내장된 CA 공개 키로 암호화된 SSL 인증서를 복호화한다. 이후 Finished 패킷을 보내 TLS handshake를 종료한다.
5. Application Data
클라이언트와 서버가 서로 TLS 를 통해 암호화 통신을 하는 데이터 패킷이다.
3️⃣ Wireshark 를 이용한 패킷 분석
Wireshark 를 이용해 TLS 1.3 handshake 과정을 분석해봤다.
야후 (https://www.yahoo.com) 에 접속할 때 어떤 일이 발생하는지 확인할 수 있었다.
1. 3-way handshake
처음 야후에 접속을 하면 https의 기본 포트인 443 으로 SYN 패킷을 전송한다.
이후 야후에선 SYN, ACK 패킷을 전송하고 내 pc는 다시 ACK 패킷을 전송하면서 3-way handshake가 진행됐다.
2. Client Hello
우선 지원하는 암호화 방식들(Cipher suites)을 확인해보자.
총 16개의 암호화 방식들이 존재한다. 이후 서버에 해당 리스트를 보내고, 서버는 이 중 하나를 선택하게 되는 것이다.
다음으로 지원하는 인증/해쉬 알고리즘을 확인해보자.
총 8개의 암호화 알고리즘이 존재한다.
그런데 한 가지 궁금한 점이 생겼다. 처음 이것을 발견하고 찾아보니 해당 내용을 블로그에 올려주신 분이 있었다.
Wireshark에선 분명 TLSv1.3 이라고 명시해주었는데, 1.2 버전으로 되어있었다. 안내문을 번역, 요약하면 다음과 같다.
"초기 테스트에서 개발자는 버전 값을 업데이트하는 것이 거의 불가능하다는 것을 깨달았습니다. TLS 1.2에서 1.3으로 연결하면 많은 프록시와 게이트웨이에서 TLS 핸드셰이크가 실패합니다. 새로 온 사람은 지원되는 버전을 확장하여 타협해야 합니다. 서버가 TLS 1.3을 지원하지 않으면 목록에 있는 TLS 1.2로 장애 복구됩니다."
대충 기존의 1.2 버전을 1.3으로 바꾸면 많은 장애가 생기기 때문에 사용자는 서비스에 따라 지원하는 버전을 확인하고 확장해야한다는 말인 것 같다. 실제로 지원하는 TLS 버전 목록엔 TLS 1.2, TLS 1.3 두 버전이 있었다. 만약 TLS 1.2로 사용하겠다면 브라우저 설정을 바꿔주자.
실제로 전송되는 정보들을 살펴보면 클라이언트가 지원하는 TLS 버전, 무작위 바이트 문자열, 세션 ID, 인증/해쉬 및 암호화 알고리즘 목록 등을 함께 전송한다.
3. Server Hello / Change Cipher Spec (Server)
우선 서버에서 결정한 암호화 방식과 키 교환 알고리즘을 살펴보겠다.
암호화 방식은 AES_128_GCM_SHA256 를 선택, 키 교환 알고리즘은 ECDHE x25519 를 사용한다.
4. Change Cipher Spec (Client)
참고
https://steady-coding.tistory.com/512
https://www.cloudflare.com/ko-kr/learning/ssl/transport-layer-security-tls/