HTTPS·TLS — 엿보기·변조·사칭을 막다
지금까지 본 HTTP는 평문이다 — 요청과 응답이 케이블을 따라 그대로 흐른다. 중간의 라우터·공용 Wi-Fi·통신사 누구든 내용을 읽고, 몰래 바꾸고, 심지어 다른 서버인 척 가로챌 수 있다. 이걸 막는 게 HTTPS — 곧 HTTP를 TLS라는 보안 계층 위에 얹은 것이다. TLS가 보장하는 건 세 가지다 — 기밀성(엿봐도 못 읽음), 무결성(바뀌면 들킴), 인증(상대가 진짜인지 확인). 이 셋을 어떻게 동시에 이루는지를 본다.
빠른 자물쇠와 느린 자물쇠 — 대칭과 비대칭
암호에는 성격이 다른 두 종류가 있다. 대칭키는 같은 키로 잠그고 푼다 — 빠르지만 그 키를 어떻게 상대에게 안전하게 전달하느냐가 문제다(키를 보내다 도청당하면 끝). 비대칭키는 공개키로 잠그면 개인키로만 풀린다(반대도) — 키 전달 문제가 없지만 수십~수백 배 느리다. TLS는 둘을 영리하게 조합한다. 느린 비대칭으로 대칭키를 안전하게 합의하는 악수(핸드셰이크)만 하고, 그 뒤 실제 데이터는 빠른 대칭키로 암호화한다. (출처: Cloudflare — TLS Handshake.)
CS 연결 — "비대칭은 안전한데 왜 안 그걸로 다 안 하나?"의 답은 비용이다. 비대칭(RSA·ECC)은 큰 수의 모듈러 지수승 같은 무거운 연산이라 CPU를 많이 먹는다. 그래서 키 교환·인증이라는 한 번의 비싼 일에만 쓰고, *대량 데이터는 싼 대칭(AES-GCM·ChaCha20)*에 맡긴다 — 비싼 자원은 꼭 필요한 한 번만이라는, 이 노트 전체에 흐르는 발상이다.
진짜 그 서버가 맞나 — 인증서와 CA
암호화만으론 부족하다 — 공격자와 안전하게 암호화 통신해 봐야 소용없다. 그래서 상대가 진짜인지 확인하는 인증이 필요하다. 서버는 인증서를 내미는데, 거기엔 서버의 공개키와 신뢰할 수 있는 기관(CA)의 디지털 서명이 들어 있다.
브라우저는 미리 신뢰하는 루트 CA 목록을 들고 있어, 서버 인증서가 그 루트까지 이어지는 체인인지, 만료되지 않았는지, 호스트명이 맞는지, 폐기되지 않았는지를 검증한다. 결정적으로 — 서버는 핸드셰이크를 자기 개인키로 서명해 보낸다. 브라우저가 인증서의 공개키로 그 서명을 확인하면, "이 서버가 인증서에 적힌 개인키를 진짜 갖고 있다"가 증명된다 — 남의 인증서를 훔쳐 흉내 내는 것을 막는 핵심이다. (출처: Certificate chain validation.)
더 빠르게 — TLS 1.3과 0-RTT
핸드셰이크는 *왕복(RTT)*을 잡아먹어 첫 응답을 늦춘다. TLS 1.3은 이를 1-RTT로 줄였고(클라이언트가 키 교환 파라미터를 첫 메시지에 바로 보내), *순방향 비밀성(forward secrecy)*을 필수로 만들었다 — 나중에 개인키가 털려도 과거 통신은 못 푼다. 더 나아가 재접속에는 0-RTT가 있다 — 이전에 합의한 *사전 공유 키(PSK)*로 첫 메시지부터 암호화된 요청을 바로 보낸다(왕복 0번).
실무에서는 — 0-RTT의 그늘과 인증서 운영. 0-RTT는 빠르지만 *순방향 비밀성이 없고, 같은 요청이 *재전송(replay)될 위험이 있다. 그래서 표준은 0-RTT를 멱등 요청(GET)에만 허용하라고 권한다 — 여기서도 멱등성(같은 요청을 두 번 처리해도 안전함)이 안전의 열쇠다(HTTP 편 연장). 그리고 운영에서 가장 흔한 보안 장애가 인증서 만료다 — 어느 날 갑자기 모든 사용자가 "안전하지 않음" 경고를 본다. 그래서 Let's Encrypt 같은 자동 갱신과 만료 모니터링이 필수다. HSTS로 브라우저가 항상 HTTPS만 쓰게 강제하고, 서비스 간 통신엔 양쪽이 서로 인증서를 검증하는 mTLS(서버만이 아니라 클라이언트도 인증)를 쓰기도 한다.
정리하면, HTTPS는 평문 HTTP를 TLS 위에 얹어 — 기밀성·무결성·인증을 더한다. 느린 비대칭으로 대칭키를 안전하게 합의하고 빠른 대칭으로 데이터를 암호화하며, CA가 서명한 인증서와 개인키 서명으로 진짜 서버임을 증명한다. TLS 1.3은 핸드셰이크를 1-RTT로 줄이고 순방향 비밀성을 보장하며, 0-RTT는 빠르지만 멱등 요청에만 안전하다 — 실무에선 인증서 자동 갱신·HSTS·mTLS가 그 위에서 보안을 떠받친다. 이제 이 모든 프로토콜을 코드에서 실제로 다루는 창구 — 소켓을 볼 차례다.