TLS(SSL) - 3. Handshake
안녕하세요, 소들입니다 :D
이번엔 TLS의 마지막 포스팅을 장식하려고 합니다!
지난 포스팅에서 공부한 것은 모두 기억하고 있죠!?
이번엔 TLS의 Handshake 부분에 대해 공부해보려고 해요.
이 부분까지 한다면 TLS의 이론은 끝났다고 봐도 무방해요!!!
다음 주엔 iOS에서 TLS Socket 통신하는 방법을 포스팅 할까 합니다. (◕‿‿◕。)
1. Handshake란?
먼저 Handshake가 뭘까요?
말 그대로 악수예요.
client : 서버야 안녕~ 너 살아 있니? 나 너랑 통신하고 싶은데 통신할 수 있는 환경이니?
server : ㅎㅇㅎㅇ~ 괜찮은듯~ 그래 통신하자 ~
이런 식으로 실제 데이터를 주고 받기 전,
서버와 클라이언트가 서로 악수를 하며 연결할 수 있는지 상태를 살피는 것이에요.
대표적으로 TCP의 3-Way Handshake 라고 들어보신 분도 있을 거예요:D
(여기선 다루지 않습니다.)
그렇다면 TLS에서 Handshake는 어떤 것을 의미 할까요?
먼저 TLS에선, 클라이언트는 서버의 인증서를 받아 서버의 무결성을 확인하고,
서버가 신뢰할 수 있는 서버라면, 암호화 통신에 사용할 대칭키를 서버의 공개키로 암호화 하여 전달한다 했어요.
그 뒤로 클라이언트의 대칭키를 알아낸 서버는 그 대칭키로 암호화를 하여 서로 데이터를 주고 받는다고 했죠?
여기서 데이터를 주고 받기 바로 전,
서버의 무결성 확인하고 대칭키를 전달하는 과정
이 과정이 바로 TLS의 Handshake를 통해서 이루어진답니다.
이 과정 외에도,
서로 TLS version 확인하고 암호화 방식, 해시 방식을 협상하는 것도 한답니다:D
자 그럼 TLS Handshake 과정을 살펴 봅시다.
Wireshark로 www.naver.com에 TLS로 접속하려 할 때,
실제 패킷이 어떻게 오가는지도 확인해 볼 거예요 :)
2. TLS의 HandShake
① Client Hello (Client)
가장 첫 번째 단계입니다.
이 과정에서 클라이언트는 서버에 접속합니다.
클라이언트가 서버에게 Client Hello라는 메세지를 날리는 거예요.
실제 Client Hello라는 패킷을 날리고 있죠?
그 패킷 안에 들어 있는 메세지 정보는 다음과 같습니다.
TLS version
Client에서 사용하는 TLS version입니다.
Cipher Suite List
Client가 지원하는 암호화 방식들입니다.
(대칭키 암호화 시스템 + 공개키 암호화 시스템 + 해시함수)
서버와 클라이언트가 서로 지원하는 암호화 방식이 다를 수 있으니,
Handshake를 통해 어떤 암호화 방식을 사용할 것인지를 정해야 합니다.
Client Random Data
클라이언트에서 생성한 난수입니다.
이는 나중에 대칭키를 만들 때 사용할 것입니다.
Session ID
TLS 통신에서 Handshake를 하는 과정은 당연히 시간이 소요되는 작업입니당.
이 작업을 매번 연결 할 때마다 하려면 시간적으로 너무 비효율적이니,
최초 한번의 Handshake만 Full Handshake를 하기로 하자! 해서 사용하는 것이 Session ID 입니다.
최초 Handshake에선 Session ID가 0으로 없고, 이후 이어지는 Server Hello 메세지를 통해 서버는
Session ID를 보내줍니다. 그러면 클라이언트는 이 Session ID를 로컬에 저장해 둡니다.
이제 다시 이 서버와 Handshake를 맺을 땐, 이 이전에 로컬에 저장해 뒀던 Session ID를 보내면
서버에선 이 Session ID를 다시 사용해도 좋다! 하면 ServerHello에 같은 Session ID를 보내줍니다.
그렇게 되면, 서버의 인증서를 확인하고 암호화 방법을 선정하고 대칭키를 교환하는 등의 작업을 하지 않습니다.
시간 상 100ms 정도 절약된다고 하네요 :D
SNI(Server Name Indication)
서버의 이름을 표시하는 부분입니다.
기존까지는 IP 주소와 도메인이 1대1 대응이라 인증서를 사용함에 문제가 없었지만,
요즘에는 IP 주소 하나에 여러 개의 도메인이 연결되기 때문에 문제가 됩니다.
(서버에서 발행한 인증서 하나에 모든 도메인을 명시하는 것이 사실상 불가능 하고
그렇다고 도메인마다 모든 인증서를 발급받는 것 또한 매우 비효율적.)
따라서 IP 주소에 접속할 때, 어떤 도메인에 접속하는 지 명시하는 부분이 이 SNI 입니다.
SNI 를 이용하면 물리적으로 동일한 서버에 존재하는 각기 다른 도메인들이 서로 다른 TLS 인증서를 적용할 수 있습니다.
근데 좀 허술한 것은.. 위 패킷 사진에서도 보이듯이 이 SNI를 전송할 때 평문(암호화 하지 않음)으로 전송 합니다.
따라서 스니핑이 가능하고, 사용자가 접속하고자 하는 도메인이 노출되겠죠..
(뭐 이런 문제 때문에 TLSv1.3에서는 SNI를 암호화 한다는 말을 들은 것 같은데 ..긁적)
② Server Hello (Server)
이번엔 클라이언트가 보낸 Client Hello에 대해 서버에서 응답을 하는 것입니다.
Server Hello 메세지에 해당하는 정보는 다음과 같습니다.
거의 Client Hello와 동일 합니다.
TLS Version
Server에서 사용하는 TLS Version입니다.
Selected Suite
Client가 보낸 암호화 방식 중에 서버가 사용 가능한 암호화 방식을 선택하여 보냅니다.
서버와 클라이언트가 암호화 방식에 대해 협상을 본 것입니다 :D
Server Random Data
서버에서 생성한 난수입니다.
클라이언트와 동일하게 대칭키를 만들 때 사용합니다.
Session ID
Client Hello에 Session ID가 0으로 왔다면 새로 Session ID를 생성해 보낼 것이고,
만약 Session ID가 0이 아니라면, 그 Session ID가 유효한지 확인하고 보내겠죠? :D
SNI(Server Name Indication)
Server에선 SNI를 비워서(Empty) 보냅니다.
③ Server Certificate (Server)
서버의 인증서를 클라이언트에게 보내는 단계입니다
필요에 따라 CA의 Certificate도 함께 전송한다고 합니다.
이제 클라이언트는 이 메세지를 통해 서버의 인증서가 무결한지 검증합니다.
서버의 인증서에 대한 검증이 OK! 로 끝났으면,
이전에 주고 받았던 클라이언트의 난수와 서버의 난수를 조합하여
pre master secret 이라는 키를 생성합니다.
바로 대칭키에 해당하는 부분입니다 :D
이제 이 pre master secret(대칭키)를 서버의 공개키로 암호화 합니다.
(이전 포스팅에서 다 다뤘던 내용이죠? XD)
● Server Key Exchange는 뭐죠? : ECDHE라는 key 쌍을 만들어 보내는 것인데, 생략하고 보셔도 무관합니다 :D
④ Server Hello Done (Server)
서버가 클라이언트에게 보낼 메세지를 모두 보냈다는 뜻으로
보내는 메시지입니다.
⑤ Client Key Exchange (Client)
클라이언트는 만들어둔
pre master secret 키를 서버의 공개키로 암호화한 것을 서버에게 보냅니다.
⑥ Key Generation (Server & Client)
딱히 통신 과정은 아니고,
클라이언트와 서버가 서로 암,복호화 할 때 사용할 대칭키를 성공적으로 공유 했다 정도로
보면 될 것 같습니다.
⑦ Cipher Spec Exchange (Server & Client)
이 이후로 전송되는 모든 메세지는 협상된 알고리즘과,
키를 이용하여 암호화 하겠다!
하고 서로에게 일종의 알림 메세지(?)를 보내는 것입니다.
⑧ Finished (Server & Cleint)
Client와 Server가 TLS Handshake를 성공적으로 마치고 종료하는 부분입니다.
+ Application Data (Server & Cleint)
Server와 Client가 서로 TLS로 암호화 통신을 하는 데이터 패킷 입니다.
.
.
.
자 이렇게 해서 TLS의 Handshake 과정도 모두 살펴봤습니다 :D
이전 포스팅을 모두 제대로 공부 했다면
어려운 부분이 없었을 것이라 생각해요!
사실 이번 iOS TLS Socket 개발을 하며 느낀 것이지만..
이렇게 자세히 알지 않아도 됩니다.. 허허
코드로는 허무할 정도로 몇 줄만 추가해주면 모두 알아서 해주거든요.
Handshake든, 대칭키를 만들든, 암호화 통신을 하든 뭐 그런 작업들을 모두요.. =ㅅ=
그렇지만 자세히 공부한 이유는,,
첫 번째로 공부하며 재밌기도 했고 (보안에 대한 흥미가 생김)
두번 째론 개발자면 이정도는 알아야하지 않나 했고,
세 번째론 코드 한줄로 모든 게 해결 되지만, 실제 매커니즘이 궁금했기 때문입니다.
나 TLS 개발 했어! 라고 말해놓고 누군가 TLS가 뭐야! 하고 묻는다면
TLS란 이런 거야! 하고 당당히 대답하고 싶었달까여..? 호호..
뭐 어쨌거나 저쨌거나 그래서 이렇게 포스팅을 쓰게 됐습니다.
3번에 걸쳐 써서 힘들기도 했지만, 오히려 포스팅을 하며 더 많이,
혹여나 잘못된 정보를 쓸까봐 더 열심히 공부하며 포스팅 한 것 같아요 o(*▽*)/
한 명에게라도 조금 더 쉽게 이해가 가길 바라는 마음으로 풀어 썼고,
혹시 이해가 가질 않거나 틀린 부분, 오타가 있다면 언제든 댓글 달아 주세요 :D
읽어주셔서 감사합니다.