TLS: 인증된 통신 경로 만들기
TLS는 전송 중 기밀성과 무결성을 제공하고 통신 상대를 인증하는 데 쓰인다. 핸드셰이크의 인증·키 합의와 실제 데이터 암호화를 구분해 이해한다.
개념부터 찾아보기
정의·역할·동작 원리를 독립 페이지에서 확인하세요. 본문의 밑줄 용어에도 설명이 있습니다.
이 노트에서 설명할 수 있게 되는 것
- TLS 1.3의 평문 메시지와 암호화된 메시지 경계를 표시한다.
- 인증서·CertificateVerify·Finished의 목적을 구분한다.
- 키 합의부터 애플리케이션 키 도출까지 상태 변화를 설명한다.
01개념과 구성 요소
- 보호 대상는 통신 상대의 인증, 전송 기밀성, 전송 중 변조 검증을 제공한다.
- 역할 분리인증서·서명은 상대 인증, 임시 키 합의는 공유 비밀 생성, 는 레코드 보호를 담당한다.
- 기본 흐름의 전제아래 순서는 ··클라이언트 인증이 없는 전체 핸드셰이크다.
02TLS 1.3 전체 핸드셰이크의 메시지 순서
- 클라이언트가 지원 버전·스위트·그룹·서명 방식과 를 보낸다.
- 서버가 선택 결과와 를 보낸다. 양쪽은 임시 공유 비밀과 문맥으로 방향별 핸드셰이크 키를 도출한다.
- 암호화된 서버 정보서버가 EncryptedExtensions와 Certificate를 핸드셰이크 키로 보호해 보낸다. 클라이언트는 이름·인증서 경로를 검증한다.
- 서버의 두 증명 서명으로 개인키 소유를 확인하고 로 공유 비밀·누적 핸드셰이크 문맥의 일치를 검증한다.
- 클라이언트 클라이언트가 자신의 를 보내고 서버가 검증한다. mTLS나 재개 연결은 이 기본 메시지 흐름과 다르다.
- 애플리케이션 보호별도 트래픽 키와 로 HTTP 등을 보호한다. 서버 데이터는 허용된 상태에서 클라이언트 보다 먼저 전송될 수도 있다.
03TLS에서 인증·키 합의·레코드 보호는 다른 일이다
- 의 보호는 연결 상대의 인증, 전송 중 기밀성, 전송 중 변조 탐지를 결합한다. HTTPS는 이 보호된 경로 위에서 HTTP를 전달하는 사용 방식이다.
- 키 역할인증서의 공개키로 모든 HTTP 본문을 계속 암호화하는 구조가 아니다. 현대적인 인증서 기반 연결에서는 인증서 키가 상대 인증에 사용되고, 임시 키 합의로 만든 비밀에서 대칭 트래픽 키를 도출한다.
- 기본 흐름의 전제기본 흐름은 ··클라이언트 인증이 없는 전체 핸드셰이크다. 세션 재개와 mTLS에서는 메시지가 추가되거나 생략된다.
- 세 가지 경계또한 패킷, 레코드, 핸드셰이크 메시지는 서로 다른 경계다. 하나의 메시지가 여러 세그먼트로 나뉘거나 여러 메시지가 한 세그먼트에 실릴 수 있다.
04ClientHello: 지원 목록과 임시 공개값을 제시한다
- 클라이언트 제안클라이언트는 지원 버전, 암호 스위트, 랜덤 값, 지원 그룹과 , 서명 알고리즘 등 협상 재료를 보낸다. SNI는 같은 서버 주소에서 어떤 서비스 이름으로 접속하는지 알리는 확장이고 ALPN은 HTTP/2 같은 상위 프로토콜을 협상하는 확장이다.
- SNI·ALPN단순히 서버 포트에 연결했다고 사용할 버전과 인증 방식이 정해지는 것은 아니다.
- 스위트의 의미의 TLS_AES_128_GCM_SHA256 같은 스위트 이름은 레코드 보호용 와 키 스케줄에 사용하는 해시를 나타낸다. 서버 인증서가 인지 ECDSA인지, 어떤 ECDHE 그룹을 쓸지는 별도 협상 정보다.
- 평문 메타데이터초기 는 일반적인 에서 평문 관찰 대상이므로 본문이 암호화되어도 모든 접속 메타데이터가 자동으로 숨겨지는 것은 아니다.
05ServerHello와 키 공유: 같은 비밀을 각자 계산한다
- 서버 선택서버는 제안된 범위에서 선택 결과와 서버 를 보낸다. 각 참여자는 자기 임시 개인값과 상대 공개값으로 공유 비밀을 계산한다.
- 공유 비밀·재시도양쪽이 같은 결과에 도달하지만 세션 키 자체를 패킷에 싣는 것은 아니다. 제안한 키 공유가 적절하지 않은 경우 HelloRetryRequest로 다른 조건의 재시도를 요청하는 경로도 있어 항상 왕복 횟수가 동일하지는 않다.
- 키 스케줄 기반 키 스케줄은 공유 비밀과 핸드셰이크 메시지의 해시 문맥을 사용하여 용도별 비밀을 만든다. 핸드셰이크 트래픽 비밀과 애플리케이션 트래픽 비밀, 클라이언트 방향과 서버 방향은 구분된다.
- 방향별 키동일 공유 비밀을 그대로 양방향 키로 사용하는 그림은 이 분리를 생략한 것이다.
06ServerHello 뒤에 암호화 경계가 생긴다
- 암호화된 메시지두 Hello를 통해 핸드셰이크 키를 도출하면 서버의 EncryptedExtensions, Certificate, , 는 그 단계의 키로 보호된다.
- ALPN 선택EncryptedExtensions에는 에 실리지 않는 추가 협상 결과가 들어가며 ALPN 선택도 대표적인 예다. 따라서 수동 PCAP에서 뒤에 암호문이 보인다고 즉시 HTTP 데이터가 시작됐다고 단정할 수 없다.
- 인증서 암호화에서는 서버 인증서 내용도 이 암호화된 구간에 속한다. 패킷만 가진 제3자가 언제나 인증서의 SAN과 전체 HTTP를 읽을 수 있는 것은 아니다.
- 분석 조건endpoint의 세션 비밀을 사용하는 허가된 분석이나 종료 지점의 관찰은 추가 조건을 가진 별도 상황이다. 원본 그림의 녹색 메시지는 바로 이 경계를 학습하기 위한 표시다.
원본에서 읽는 TLS 1.3 암호화 경계
원본 크기로 보기 ↗이 자료에서 읽어낼 것
- ClientHello·ServerHello 뒤에 Handshake 키 생성이 놓인다. 이후 녹색 서버 메시지에는 인증서도 포함된다.
- CertificateVerify는 개인키 소유 증명, Finished는 합의된 비밀과 핸드셰이크 문맥 확인으로 구분되어 있다.
- 맨 아래 애플리케이션 화살표는 개념상 묶은 표시다. 화살표 하나가 TCP 패킷 하나라는 뜻은 아니다.
07Certificate: 키를 이름과 신뢰 경로에 묶는다
- 인증서 체인서버는 리프 인증서와 필요한 중간 CA 인증서를 전달한다. 클라이언트는 인증서 서명 경로를 로컬 신뢰 기준에 연결하고, 요청한 이름과 SAN, 유효기간, 용도와 경로 제약을 평가한다.
- 루트 신뢰루트 인증서를 서버가 함께 보낸다는 사실만으로 새로운 루트를 신뢰해서는 안 된다.
- 공개키와 이름이 단계가 성공하면 공개키와 서비스 이름을 연결할 수 있지만 현재 연결 상대의 개인키 소유 증명은 아직 별도로 필요하다. 유효한 인증서 파일은 누구나 복사할 수 있기 때문이다.
- 별도 소유 증명인증서 체인을 보냈다는 사실과 이번 핸드셰이크의 키 합의가 인증되었다는 결론을 구분해야 다음 메시지의 의미가 보인다.
08CertificateVerify와 Finished가 증명하는 차이
- 는 서명 알고리즘이 정한 문맥과 지금까지의 핸드셰이크 해시를 개인키로 서명한다. 클라이언트는 인증서 안의 공개키로 검증하여 연결 상대가 대응 개인키를 가졌고 이번 협상 문맥에 참여했음을 확인한다.
- 개인키 소유단순히 인증서를 복사한 중간자는 이 서명을 정상적으로 만들 수 없다.
- 는 핸드셰이크 비밀로부터 도출된 키와 누적 메시지 해시에 기반한 검증값이다. 서명을 다시 한 번 보내는 메시지가 아니라 키 합의와 핸드셰이크 문맥에 대한 확인이다.
- 양쪽 검증클라이언트는 서버 를 검증하고 자신의 를 보내며 서버도 이를 검증한다. Hello 메시지의 협상 내용이 중간에서 바뀌면 양쪽이 같은 문맥을 계산하지 못해 검증이 실패할 수 있다.
09애플리케이션 레코드와 태그 검증
- 트래픽 키애플리케이션 트래픽 키는 핸드셰이크 보호 키와 구분해 도출된다. HTTP 요청·응답은 레코드 계층에서 로 보호되고 수신자는 태그 검증이 성공한 데이터만 상위 계층에 전달한다.
- 방향과 순서방향마다 다른 키와 레코드 순서 문맥을 사용하므로 반대 방향에서 본 암호문을 그대로 가져와 정상 요청처럼 처리하는 구조가 아니다.
- 서버 송신 시점서버는 허용되는 핸드셰이크 상태에서 클라이언트의 최종 메시지 전에도 애플리케이션 데이터를 보낼 수 있는 경우가 있다. 입문 흐름도에서 모든 애플리케이션 화살표를 맨 아래에 묶는 것은 전체 절차를 단순화한 표현이다.
- 도식의 한계도식의 화살표 하나를 패킷 하나나 모든 구현의 정확한 송신 시점으로 해석하지 않는다.
10TLS 1.3 레코드의 내부 평문과 Nonce
- 내부 평문TLSInnerPlaintext는 실제 content, 1바이트 content type, 선택적 0 패딩으로 구성된다. 실제 유형도 암호화 구간 안에 있다.
- 외부 헤더TLSCiphertext의 외부 유형은 application_data이며 legacy_record_version은 0x0303이다. 이 값만 보고 1.2라고 판정하지 않는다.
- 인증 추가 자료외부 유형·버전·길이를 연결한 5바이트 헤더가 의 additional data에 들어가므로 암호화되지 않아도 인증된다.
- 레코드 방향별 레코드 순서 번호를 IV 길이에 맞춰 0으로 채운 값과 write IV를 XOR해 를 만든다.
- 키 문맥송수신 방향과 키 세대마다 상태를 구분한다. 키를 바꾸면 해당 방향의 순서 번호도 0에서 다시 시작하며, 다른 세대의 키·순서 번호를 섞으면 검증에 실패한다.
11100바이트 내용의 가상 TLS 레코드 길이
- 조건 고정의 16바이트 태그를 사용하고 content는 100바이트, 추가 패딩은 없다고 가정한다.
- 내부 길이Content 100바이트와 실제 유형 1바이트를 합쳐 입력 평문은 101바이트다.
- 암호화 길이암호문과 태그는 101+16=117바이트이며 외부 length 필드는 이 값을 표현한다.
- 전송 크기 헤더 5바이트를 더하면 레코드는 122바이트다. ·IP· 오버헤드는 포함하지 않은 계산이다.
- 관찰 한계PCAP의 세그먼트 하나가 반드시 122바이트인 것은 아니다. 분할·병합·추가 레코드 때문에 경계가 달라질 수 있다.
12복호화·Finished 오류를 구분하는 증거
- Handshake 문맥· 실패는 서로 다른 키와 입력을 검증한다. 인증서 경로 오류와 누적 메시지 불일치를 분리한다.
- Record 오류 실패는 키··헤더 AAD·암호문의 조합이 맞지 않다는 뜻이다. 악의적 변조 외에 잘못된 세션 비밀·누락 레코드도 분석 실패 원인이다.
- 방향·세대클라이언트·서버의 트래픽 키를 뒤집거나 KeyUpdate 이후에도 이전 키를 적용하지 않았는지 확인한다.
- 연결 상태RFC의 bad_record_mac 종료와 애플리케이션 HTTP 오류는 다른 계층이다. 가 성립한 뒤 403을 받은 것을 암호 복호화 실패로 기록하지 않는다.
13Forward Secrecy는 장기 인증키와 임시키를 분리한 결과다
- 임시 키 합의ECDHE 같은 임시 키 합의는 연결마다 다른 비밀 재료를 사용한다. 공격자가 트래픽을 기록한 후 서버의 장기 인증 개인키를 얻더라도 그 키만으로 과거 연결의 임시 공유 비밀을 바로 계산할 수 없게 하는 성질이 Forward Secrecy다.
- 키 역할 분리그래서 인증서 개인키와 트래픽 키의 역할을 분리해서 이해해야 한다.
- 세션 비밀 노출이는 모든 형태의 유출을 막는다는 뜻은 아니다. 실행 중 메모리에서 해당 세션 비밀이 탈취되거나 endpoint가 이미 침해되면 별개의 문제가 생긴다.
- 보호 경계는 애플리케이션 내부 권한 오류, 저장된 비밀번호, 이미 복호화된 서버 메모리까지 자동으로 보호하는 경계가 아니다.
14TLS 1.2와 1.3을 비교할 때 남겨야 할 조건
- 버전별 협상 1.2는 스위트에 키 교환·인증·대칭 암호·해시 선택이 함께 표현되는 경우가 있고 다양한 과거 선택지를 포함한다. 은 키 합의·서명 협상과 선택을 분리하며 레거시 방식들을 제거하고 더 많은 핸드셰이크 메시지를 암호화한다.
- 메시지 보호일반적인 전체 연결의 지연 설명에서 1.2의 2-RTT와 1.3의 1-RTT가 비교된다.
- RTT 비교 조건이 비교는 연결 시간, 재시도, 세션 재개 등 조건을 생략한 핸드셰이크 비교다. 1.2라는 버전 이름만으로 안전성 전체를 단정할 수 없고 실제 스위트와 인증 검증이 중요하다.
- 버전과 설정반대로 도 이름 검증을 끈 클라이언트나 유출된 endpoint 비밀을 스스로 해결하지 못한다.
15세션 재개·PSK와 0-RTT의 재생 위험
- 재개은 이전 연결에서 얻은 정보로 기반 재개를 할 수 있다. 재개 시의 인증·키 도출 경로는 처음 인증서 교환을 하는 연결과 다르며 와 새로운 키 합의를 결합하는지에 따라 성질도 달라진다.
- 메시지 생략따라서 “모든 연결은 매번 똑같은 인증서 전체 교환을 한다”는 설명은 맞지 않는다.
- 재생는 핸드셰이크 완료 전에 early data를 보낼 수 있게 한다. 지연을 줄이는 대신 정상적인 재전송과 다른 재생(replay) 공격 위험을 고려해야 한다.
- 요청 의미한 번만 처리되어야 할 상태 변경이 다시 처리되면 피해가 생기므로 애플리케이션의 요청 의미와 재생 방지 정책이 중요하다. 단순히 암호화되어 있다는 이유로 결제 같은 동작에 무조건 안전하다고 판단하지 않는다.
16mTLS와 인가는 서로 다른 단계다
- 클라이언트 인증mTLS에서는 서버가 CertificateRequest로 클라이언트 인증서를 요청할 수 있고 클라이언트는 인증서와 개인키 소유를 증명하는 를 전달한다. 서버는 클라이언트 인증서의 신뢰 경로·용도·정책과 서명을 평가한다.
- 인증 방식이는 사람이 비밀번호를 입력하는 방식과 다른 인증 증거를 사용하는 것이다.
- 서비스 인증된 서비스나 기기에 어떤 API·문서·관리 기능을 허용할지는 이후 정책이 결정한다. 또한 프록시가 를 종료하면 브라우저→프록시와 프록시→백엔드는 다른 보안 구간이다.
- 프록시 구간전단의 HTTPS 표시만으로 후단이 암호화되었거나 인증되었다고 판단하지 않는다. 프록시가 전달한 사용자 정보 역시 백엔드가 신뢰할 수 있는 경로에서만 받아야 한다.
17오류 위치를 메시지 상태와 연결하기
- 오류 단계공통 버전·스위트가 없으면 Hello 협상 단계에서 진행하지 못한다. 신뢰하지 않는 CA나 이름 불일치는 인증서 검증에, 키 불일치는 서명과 개인키 소유 증명에, 문맥·비밀 불일치는 에 영향을 줄 수 있다.
- HTTP 403가 정상적으로 끝난 뒤 HTTP 403이 나온다면 전송 암호화 실패와 애플리케이션 권한 거부를 구분할 수 있다.
- 원본 도식 읽기원본 캡처에는 와 , 키 생성, 서버 인증 메시지와 양쪽 가 차례대로 표시되어 있다. 이 순서 위에 실제 실패 지점을 놓으면 “SSL 연결이 안 된다”는 현상을 협상·신원·키 확인·업무 처리로 나눌 수 있다.
- 다중 경로 진단인증서 갱신 후 일부 경로만 실패하는 상황은 로드밸런서별 인증서와 후단 설정까지 함께 설명한다.
설명과 함께 보는 보조 도식
모식도 · TLS 1.3의 암호화 경계
인증서 기반 전체 핸드셰이크. PSK·0-RTT·mTLS는 생략했다.
ClientHello
지원 매개변수와 클라이언트 키 공유를 전송한다.
- 메시지
- 평문
전체 단계를 한 번에 읽기
- 01
ClientHello
지원 매개변수와 클라이언트 키 공유를 전송한다.
- 메시지
- 평문
- 02
ServerHello
선택한 매개변수와 키 공유를 전달하고 핸드셰이크 키를 도출한다.
- 다음 메시지
- 핸드셰이크 키로 보호
- 03
인증 메시지와 Finished
EncryptedExtensions·Certificate·CertificateVerify·Finished를 전달한다.
- 04
상대 검증
체인과 이름, 서명 및 핸드셰이크 검증값을 확인한다.
- 검증 실패
- 연결 중단
- 05
Client Finished
클라이언트의 핸드셰이크 검증값을 보낸다.
- 06
애플리케이션 데이터
용도와 방향별 애플리케이션 트래픽 키로 레코드를 보호한다.
- 키
- 핸드셰이크 키와 구분
핸드셰이크의 암호화 경계와 인증 실패 위치 찾기
메시지 순서를 패킷 관찰 가능 범위와 연결하고, 인증서 오류가 발생하는 단계를 설명한다.
실습 구성과 전제
- 자신의 실습 서버에 정상 HTTPS 연결을 한 번 만들고 PCAP를 저장한다.
- 전체 핸드셰이크 도해를 기준으로 하되 재개 연결·· 1.2는 별도로 구분한다.
암호화되기 전 협상 필드를 찾는다
- 에서 와 의 supported_versions, cipher suite, 를 비교한다. 구버전 호환 필드만 보고 1.2라고 단정하지 않는다.
- 는 제안, 는 선택 결과다. 양쪽이 합의한 키 공유로 이후 핸드셰이크 보호 키를 도출한다.
texttls.handshake.type == 1 || tls.handshake.type == 2표시 필터 예시. 저장된 자신의 실습 PCAP에서 사용한다.
원본 크기로 보기 ↗- ClientHello와 ServerHello 다음에 'Handshake 암호화 키 생성' 경계가 표시된다.
- CertificateVerify와 Finished는 서로 다른 메시지로 그려져 있어 키 소유 증명과 핸드셰이크 무결성 확인을 나누어 읽을 수 있다.
확인 기준같은 .stream에서 협상 버전과 키 공유를 확인한다.
안 보이는 메시지와 실패한 메시지를 구분한다
- 에서는 뒤의 인증서 메시지도 보통 암호화돼 보인다. 키 로그가 없는 캡처에서 Certificate가 보이지 않는다는 이유만으로 서버가 인증서를 생략했다고 단정하지 않는다.
- 실습 클라이언트의 브라우저 오류와 패킷 시각을 연결한다. 인증서 경고는 전송 암호화의 유무와 다른 판단이다.
원본 크기로 보기 ↗- HTTPS 주소에서도 CA 신뢰 오류가 표시된다.
- 경고 화면에는 협상 cipher suite나 Finished 성공 여부가 나타나지 않는다. 이 정보는 패킷·클라이언트 진단으로 보완해야 한다.
확인 기준캡처 가시성 한계와 실제 인증 실패를 보고서에서 분리한다.
인증 성공 후 애플리케이션 동작을 확인한다
- 핸드셰이크가 끝나도 HTTP 인가나 로그인 성공이 보장되지는 않는다. 연결 성립→서버 신뢰→애플리케이션 응답을 각각 판정한다.
- 복호화 가능한 실습 PCAP에서는 정상 요청의 응답을 확인하고, 키 로그 파일은 학습 후 별도로 보호·정리한다.
확인 기준성공과 HTTP 상태 코드를 같은 항목으로 합치지 않는다.
실습에서 확인한 동작 원리
- 의 암호화 경계는 이후에 생긴다.
- 신뢰 오류·복호화 자료 부재·애플리케이션 오류는 다른 현상이다.
설정·출력 추가로 확인하기 8장
아래 화면을 펼쳐 위 실습의 설정값, 명령과 확인 기준을 비교해 보세요. 각 묶음은 별도 실습 기록입니다.
실습 화면 묶음 01 2장
원본 크기로 보기 ↗- 「프록시서버 ←→ 서버 (포트로 클라이언트 매칭)」 문맥에 삽입된 원본 실습·개념 참고 화면이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
원본 크기로 보기 ↗- 「프록시서버 ←→ 서버 (포트로 클라이언트 매칭)」 문맥에 삽입된 원본 패킷 캡처이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
실습 화면 묶음 02 1장
원본 크기로 보기 ↗- 「DVWA Redirect」 문맥에 삽입된 원본 패킷 캡처이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
실습 화면 묶음 03 1장
원본 크기로 보기 ↗- 문서 문맥에 삽입된 원본 실습·개념 참고 화면이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
실습 화면 묶음 04 1장
원본 크기로 보기 ↗- 문서 문맥에 삽입된 원본 실습·개념 참고 화면이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
실습 화면 묶음 05 1장
원본 크기로 보기 ↗- 학습 원본 · HTTPS 인증서와 브라우저 표시의 HTTPS에 수록된 화면·도식이다.
실습 화면 묶음 06 1장
원본 크기로 보기 ↗- 「Improper input validacation」 문맥에 삽입된 원본 실습·개념 참고 화면이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
실습 화면 묶음 07 1장
원본 크기로 보기 ↗- 「문제 2 ) 주피터 - 네트워크 격리되어있음 (아니었음)」 문맥에 삽입된 원본 실습·개념 참고 화면이다. TLS 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
함께 보는 학습 자료
아래 공식 자료를 본문의 개념·예제와 함께 읽어 보세요. 자료별로 확인할 위치와 관찰할 내용을 적었습니다.
RFC 8448: TLS 1.3의 실제 바이트 추적
3절의 1-RTT 교환에서 메시지 구성·키 도출·레코드 보호가 어떤 순서로 이어지는지 바이트 예와 비교할 수 있다.
- 메시지 길이와 레코드 길이의 차이
- 클라이언트·서버 방향별 handshake traffic secret
- 와 가 등장하는 위치
이해했는지 확인하기
- 접속 이름과 인증서 SAN·신뢰 경로가 맞는지 확인한다.
- TLS가 종료되는 지점과 그 뒤 통신 구간을 확인한다.
- 실제 협상 결과와 인증서 갱신 상태를 점검한다.