주소창 자물쇠는 그냥 짠! 하고 켜질 것 같죠? 사실은 그 전에 꽤 차분한 확인 절차가 한 단계씩 지나가요.TLS, SSL, 인증서는 뭐가 다를까요?에서는 브라우저가 상대를 확인하고 보호된 통로를 준비한다는 큰 그림을 먼저 봤어요. 그리고 TLS 1.3 핸드셰이크는 실제로 어떤 순서일까요?에서는
ClientHello, ServerHello, Certificate, Finished 같은 메시지들이 프로토콜 안에서 어떤 역할을 맡는지를 구조 쪽에서 해부해봤죠.
실제 장면으로 내려오면 여기서부터 또 다른 헷갈림이 생겨요.
“좋아요, 이름과 역할은 알겠어요. 근데 실제 장면처럼 따라가면 어느 단계에서 무슨 일이 벌어지는 거죠?”이 글이 필요한 이유는 딱 이거예요. 브라우저나 도구를 보다 보면 TCP는 이미 열렸는데, HTTP는 아직 안 올라오고, 중간에 TLS 줄들이 여러 개 끼어드는 장면을 자주 보게 되거든요. 그때 이 흐름을 모르면 “지금 느린 게 TCP 때문인지, 인증서 확인 때문인지, 그냥 정상 준비 단계인지” 가 잘 안 갈려요. 오늘은 가장 흔한 TLS 1.3 인증서 기반 핸드셰이크 한 장면을 기준으로, 이게 무슨 장면인지, TCP / 인증서 / 첫 HTTP 요청과 어떻게 연결되는지, 왜 확인 단계가 여러 줄로 나뉘는지, 그리고 그다음에야 어떤 순서로 읽어야 하는지 따라가볼게요. 설명의 큰 뼈대는 RFC 8446 2장과 4장, 실제 흐름 감각은 RFC 8448의 simple 1-RTT example 쪽을 바탕으로 잡아볼게요.
여기서는 현대 웹에서 가장 흔한 TLS 1.3의 기본 핸드셰이크 장면을 읽는 감각에 집중할게요. 각 메시지 필드와 변형 흐름 자체를 해부하는 일은 TLS 1.3 핸드셰이크는 실제로 어떤 순서일까요? 쪽이 맡고, 여기서는 그 구조가 실제 줄 위에서 어떤 순서와 신호로 보이는지, 그리고 왜 그 단계가 HTTP 앞에 끼어 있는지를 붙잡을 거예요.
TLS 핸드셰이크 장면부터 다시 잡아볼까요?
먼저 아주 짧게만 다시 잡고 갈게요. TLS 핸드셰이크는 이미 열린 TCP 연결 위에서,- 누구와 이야기하는지 확인하고,
- 어떤 보호 규칙으로 갈지 맞추고,
- 그 확인 절차가 안 바뀌었는지 닫는
- 먼저 어떤 방식으로 보호할지 맞춰야 하고,
- 그다음 상대가 누구인지 확인해야 하고,
- 마지막으로 방금까지의 대화가 안 바뀌었는지 닫아야 하거든요.
먼저 장면 한 컷부터 볼까요?
가장 단순한 설명용 장면은 보통 이렇게 잡아요.이 장면에서 먼저 읽어야 할 신호 네 가지
핸드셰이크를 처음 읽을 때는 세부 필드보다 어디를 먼저 봐야 하는지가 더 중요해요. 우선은 이 네 가지부터 잡으면 돼요.- TLS는 TCP가 열린 뒤에 시작돼요 — 둘을 같은 핸드셰이크로 섞어 읽으면 바로 헷갈려요.
ClientHello는 시작 신호예요 — 이제 TLS 협상 장면이 열렸다는 뜻이에요.ServerHello는 경계선이에요 — 여기서부터 TLS 1.3의 후반부 감각이 확 달라져요.- 뒤쪽 메시지들은 같은 덩어리가 아니에요 — 신원 제시, 소유 증명, 마지막 확인이 나눠져 있다는 점만 잡으면 돼요.
1단계: 먼저 TCP가 열려 있어야 해요
TLS는 허공에서 바로 시작하지 않아요. 보통은 먼저 TCP가 연결을 열고, 그 위에서 TLS가 올라와요. 이게 왜 중요할까요?- TCP는 대화할 선로를 여는 일에 가깝고,
- TLS는 그 선로 위에서 누구와 어떻게 안전하게 말할지 맞추는 일에 가깝기 때문이에요.
SYN → SYN-ACK → ACK 와, 지금 보는 ClientHello → ServerHello → ... 는 이름도 다르고 목적도 달라요.
여기서는 한 가지만 먼저 분리해서 볼게요.
여기서는 TCP 자체를 다시 길게 열지 않을게요. 아래 연결이 어떻게 열리는지 감각을 다시 붙이고 싶다면 tcpdump에서 TCP handshake는 어떻게 보일까요? 쪽이 바로 이어져요.
2단계: ClientHello 가 보이면, 이제 장면이 시작된 거예요
이 글에서는 ClientHello 의 모든 칸을 다시 해부하지 않을게요. 그건 이미 TLS 1.3 핸드셰이크는 실제로 어떤 순서일까요?에서 구조 쪽으로 열어봤으니까요. 여기서는 이 줄이 나타났다는 사실 자체가 뭘 뜻하는지만 잡아볼게요.
ClientHello 가 보이면 일단 이렇게 읽으면 돼요.
- 이제 TLS 대화가 시작됐다
- 아직은 협상 앞부분이다
- 세부 필드를 외우기보다 다음 줄로 어떻게 이어지는지 보는 게 중요하다
ClientHello 는 “암호화가 끝났다” 보다, “암호화 준비가 막 시작됐다” 쪽에 더 가까워요.
3단계: ServerHello 는 어디서 경계가 바뀌는지 알려줘요
ServerHello 를 보면 제일 먼저 떠올려야 할 질문은 이거예요.
“좋아요, 이제부터는 뭐가 달라지죠?”TLS 1.3에서는 바로 여기서 장면의 성격이 바뀌어요. 서버가 실제로 쓸 조합을 고르고 나면, 뒤쪽 메시지들은 더 보호된 후반부 감각으로 넘어가거든요. 그래서 장면을 읽을 때는
ServerHello 를 단순 응답 한 줄이 아니라, 앞단 협상과 뒷단 확인 절차를 가르는 경계선으로 보는 편이 좋아요.
4단계: 뒤쪽 줄은 “이름”보다 “역할 덩어리”로 읽으면 쉬워요
EncryptedExtensions, Certificate, CertificateVerify, Finished 를 볼 때도 이 글에서는 각 필드 구조를 다시 길게 뜯지 않을게요. 대신 장면 위에서는 지금이 어떤 확인 덩어리인지만 끊어 읽으면 훨씬 편해요.
즉 장면 감각에서는 “메시지 이름 외우기” 보다, 지금이 규칙 확인 단계인지, 신원 확인 단계인지, 마지막 무결성 확인 단계인지를 먼저 읽는 편이 훨씬 덜 헷갈려요.
5단계: 그래서 실제 장면에서는 어디까지 보이고, 어디서부터 덜 보일까요?
여기서 초심자가 제일 자주 멈춰요.“앞줄은 보이는데, 왜 뒤로 갈수록 덜 보이죠?”이건 TLS 1.3이 암호화 경계를 더 빨리 세우는 쪽으로 움직였기 때문이에요. 그래서 장면을 읽을 때는 이렇게만 기억해도 좋아요.
ClientHello,ServerHello는 협상 앞부분- 그 뒤는 확인 절차의 후반부
- 그래서 TLS 1.2 기억만으로 보면 “왜 안 보이지?” 같은 오해가 생길 수 있음
실제 도구나 구현에 따라 호환성용 ChangeCipherSpec 레코드가 잠깐 보이는 경우도 있어요. 여기서는 초심자용 기본 흐름을 먼저 붙잡고, 그런 가지는 나중에 따로 열어볼게요.
6단계: Finished 뒤에는 application data가 올라올 수 있어요
핸드셰이크를 읽을 때 자주 놓치는 포인트가 하나 더 있어요.
흔한 HTTP 요청 장면에서는 클라이언트가 자기 Finished 를 보낸 뒤 첫 요청을 올린다고 읽으면 돼요.
다만 프로토콜 경계는 방향마다 달라요. 서버는 서버 Finished를 보낸 뒤 application data를 먼저 보낼 수 있고, 클라이언트는 클라이언트 Finished를 보낸 뒤 application data를 보낼 수 있어요. 그래서 캡처에서 무조건 “양쪽 Finished가 모두 보여야 application data가 나온다” 라고 외우기보다, 각 송신자가 자기 Finished를 보냈는지를 보는 편이 더 정확해요.
그래서 End-to-End Request Debugging에서 TLS 구간이 따로 보이는 거예요. HTTP가 느린 게 아니라, 그 전에 보호 통로 준비 시간이 따로 쓰이고 있을 수 있기 때문이죠.
근데 왜 장면이 이렇게 여러 줄로 나뉠까요?
한 번에 “자, 이제 암호화!” 하고 끝내면 쉬울 것 같죠? 사실은 아니에요. TLS는 한꺼번에 해결해야 하는 문제가 여러 개라서 단계를 나눠요.1. 어떤 방식으로 말할지 먼저 맞춰야 하니까요
앞줄에서 어떤 조합으로 갈지 맞춰야, 뒤 줄이 무슨 뜻인지도 읽히기 시작하거든요.2. 상대가 누구인지 확인해야 하니까요
그냥 줄이 몇 개 오갔다고 끝이 아니에요. 내가 찾은 그 서버인지 확인되는 흐름이 따로 보여야 하거든요.3. 방금까지의 대화가 안 바뀌었는지도 확인해야 하니까요
중간 줄에서 신원과 확인 절차가 어떻게 닫히는지 보여야, 마지막 줄의 의미도 분명해져요.4. 그 다음에야 HTTP를 안심하고 올릴 수 있으니까요
결국 이 여러 줄은 쓸데없이 복잡한 장식이 아니라, HTTP가 올라오기 전에 무엇이 먼저 확인되는지 보여주는 기록이에요.그럼 진짜 TLS 장면은 어떻게 보일까요?
아까는 설명용 장면으로 봤죠. 이번에는 실제로 도구에서 만날 법한 흔적을 한 번 볼게요. 예를 들어openssl s_client -connect example.com:443 -servername example.com -tls1_3 -msg 같은 흐름에서는, 대표적으로 이런 줄을 만나게 돼요.
- 화살표 방향 — 누가 먼저 보냈는지
ServerHello뒤 경계 — 장면의 성격이 바뀌는 지점Certificate와CertificateVerify분리 — 신분 제시와 진짜 주인 증명이 다른 단계라는 점Finished두 줄 — 마지막 확인이 양쪽에서 닫히는 장면이라는 점
TLS 1.2 감각이랑 어디서 가장 많이 헷갈릴까요?
여기서는 큰 그림만 짚을게요. TLS 1.2와 TLS 1.3은 같은 이름표를 달고 있어도 장면 순서가 꽤 달라요.- TLS 1.2에는
ServerHelloDone,ChangeCipherSpec같은 감각이 더 또렷해요. - TLS 1.3에는
EncryptedExtensions가 들어오고,ServerHello뒤의 후반부가 더 빨리 보호돼요. - 그래서 TLS 1.2 화면 기억만으로 TLS 1.3 장면을 읽으면, “왜 이 줄이 안 보이지?” 같은 오해가 생기기 쉬워요.
여기서는 현대 웹에서 가장 흔한 TLS 1.3 기본 장면만 붙잡을게요.HelloRetryRequest, 0-RTT, 호환성용ChangeCipherSpec, 구버전 흐름 비교는 뒤에서 따로 열어도 충분해요.
잘못 읽기 쉬운 함정 다섯 가지
하나, TCP 핸드셰이크와 TLS 핸드셰이크를 같은 장면으로 생각하기.TCP는 연결 열기고, TLS는 그 연결 위에서 보호 규칙과 신원을 맞추는 단계예요. 둘,
Certificate 만 보이면 인증이 끝났다고 생각하기.CertificateVerify 와 Finished 까지 봐야 현재 세션 위 확인이 닫혀요.
셋, TLS 1.3에서도 예전처럼 뒤 단계가 다 평문에 오래 남는다고 생각하기.TLS 1.3에서는
ServerHello 뒤의 후반부 감각이 확 달라져요.
넷, 0-RTT를 기본 핸드셰이크의 평범한 빠른 버전이라고 생각하기.그건 재개 쪽 가지예요. 첫 이해에서는 기본 흐름과 분리해서 보는 편이 안전해요. 다섯, 자물쇠가 떴다는 걸 “암호화만 됐다” 로만 읽기.
실제로는 협상 + 신원 확인 + 무결성 확인이 지나간 결과에 더 가까워요.
자, 정리해볼까요?
- TLS 핸드셰이크는 보통 TCP가 열린 뒤에 시작돼요.
ClientHello는 장면의 시작 신호,ServerHello는 경계선, 뒤쪽 메시지들은 신원 확인과 마지막 확인 절차로 읽으면 좋아요.- TLS 1.3에서는
ServerHello뒤부터 후반부 감각이 크게 달라진다는 점이 중요해요. - 그래서 자물쇠는 단순히 “숨겼다” 보다, 상대 확인과 보호 통로 준비가 닫혔다는 뜻에 더 가까워요.
- HTTP는 그 준비 절차가 지나간 뒤에야 안심하고 올라와요.
이어서 보면 좋은 글
- TLS와 인증서의 큰 그림부터 다시 잡고 싶다면 — TLS, SSL, 인증서는 뭐가 다를까요?
- 메시지 이름과 역할을 구조 쪽에서 다시 해부하고 싶다면 — TLS 1.3 핸드셰이크는 실제로 어떤 순서일까요?
- 실제 장면에서 인증서 경고가 뜰 때, 이름 문제인지 체인 문제인지 더 구체적으로 가르고 싶다면 — TLS 인증서 체인과 신뢰 오류는 어떻게 읽어야 할까요?
- 아래 연결이 실제로 어떻게 열리는지 캡처 감각으로 다시 보고 싶다면 — tcpdump에서 TCP handshake는 어떻게 보일까요?
- 요청 하나를 끝까지 따라가며 TLS 구간이 어디인지 다시 보고 싶다면 — End-to-End Request Debugging