암호화의 기초
대칭키·공개키·키 교환·해시·MAC·디지털 서명의 서로 다른 역할과 TLS에서의 조합을 이해합니다.
HTTP는 메시지를 평문으로 보냅니다.
같은 네트워크의 관찰자는 요청 경로, 쿠키, 본문에 담긴 민감 정보를 볼 수 있고, 중간자가 응답을 바꿔치기할 수도 있습니다.
HTTPS는 이 문제를 줄이기 위해 HTTP를 TLS(Transport Layer Security) 위에 올립니다.
TLS는 요청과 응답을 암호화하고 서버 신원과 무결성을 검증하지만, 상대 IP와 시간·크기 같은 통신 흔적은 일부 남긴다.
- HTTP 평문
경로, 쿠키, 본문을 관찰자가 읽거나 응답을 바꿀 수 있다.
- TLS 경계 수립
인증서로 서버를 확인하고 이번 연결의 트래픽 키를 합의한다.
- 내용 보호
HTTP 메시지는 암호문이 되고, 레코드 변조는 검증에서 드러난다.
- 경계 밖 흔적
통신 IP, 포트, 시각, 패킷 크기 같은 메타데이터는 관찰될 수 있다.
TLS를 이해하려면 “암호화”를 하나의 기능으로 뭉뚱그리면 안 됩니다.
실제 보안 연결은 대칭키 암호, 공개키 기반 인증과 키 교환, 해시, MAC, 디지털 서명을 서로 다른 역할로 조합합니다.
대칭키 암호화
대칭키 암호화(Symmetric Encryption)는 암호화와 복호화에 같은 비밀 키를 사용하는 방식입니다.
속도가 빠르기 때문에 TLS에서 실제 애플리케이션 데이터를 보호하는 데 쓰입니다.
대칭키 암호의 강점은 빠른 처리이고, 약점은 키 공유입니다. TLS는 핸드셰이크에서 트래픽 키를 합의한 뒤 실제 HTTP 데이터는 AEAD 대칭키 암호로 보호합니다.
- 평문과 같은 비밀 키를 준비
sender 평문과 같은 비밀 키를 준비 HTTP 본문, 트래픽 키, nonce가 암호화 입력입니다. plaintext + key + nonce
- 암호문과 인증 태그를 만든다
AEAD 암호문과 인증 태그를 만든다 읽지 못하게 숨기고, 중간 수정도 태그 검증으로 잡습니다. ciphertext + tag
- 같은 키로만 복호화 가능
receiver 같은 키로만 복호화 가능 키, nonce, tag가 맞아야 원래 평문을 복원합니다. same key + nonce + tag
- 대칭키는 핸드셰이크 뒤의 record layer에서 일한다
TLS 위치 대칭키는 핸드셰이크 뒤의 record layer에서 일한다 공개키 기술은 서버를 인증하고 공유 비밀을 합의하는 데 쓰이고, 실제 요청/응답 바이트는 여기서 나온 트래픽 키로 빠르게 보호합니다. handshake secret → traffic key → encrypted records
암호화: 평문 + 비밀 키 + nonce → 암호문
복호화: 암호문 + 같은 키 + nonce → 평문
핵심: 양쪽이 같은 비밀 키를 이미 알고 있어야 한다| 알고리즘/방식 | 키 길이 예시 | 현재 실무 판단 |
|---|---|---|
| AES-GCM | 128/256비트 | TLS에서 널리 쓰이는 AEAD 방식 |
| ChaCha20-Poly1305 | 256비트 | 소프트웨어 구현에서 성능이 좋은 AEAD |
| AES-CBC + HMAC | 128/256비트 | 과거 TLS 1.2에서 사용, 구성 주의 필요 |
| DES | 56비트 | 안전하지 않아 사용하면 안 됨 |
| 3DES | 112비트 수준 | 레거시 호환 외에는 사용 중단 방향 |
대칭키 암호의 핵심 문제는 “키를 어떻게 안전하게 공유할 것인가”입니다.
네트워크에 비밀 키를 그대로 보내면 중간자가 그 키를 보고 이후 통신을 모두 읽을 수 있습니다.
그래서 TLS는 핸드셰이크에서 키 교환을 먼저 수행하고, 그 결과로 만들어진 트래픽 키를 대칭키 암호에 사용합니다.
공개키 암호와 키 교환
공개키 암호 방식은 공개키와 개인키라는 서로 다른 키를 사용합니다.
공개키는 배포할 수 있지만, 개인키는 소유자만 보관해야 합니다.
다만 현대 TLS에서 공개키 기술의 핵심 용도는 “대량 데이터를 공개키로 암호화”하는 것이 아니라 서버 인증, 서명, 키 교환입니다.
현대 TLS에서는 서명이 서버의 신원을 증명하고 ECDHE가 공유 비밀을 만든다. 실제 HTTP 레코드 보호는 여기서 파생한 대칭키가 맡는다.
- 접속한 서버가 맞는지 확인
authentication 인증서 공개키 호스트명과 신뢰 체인에 연결된 서버 키를 브라우저가 얻는다. RSA-PSS · ECDSA 서버가 개인키로 핸드셰이크에 서명하고 브라우저가 검증한다.
- 인증서 공개키
호스트명과 신뢰 체인에 연결된 서버 키를 브라우저가 얻는다.
- RSA-PSS · ECDSA
서버가 개인키로 핸드셰이크에 서명하고 브라우저가 검증한다.
- 이번 연결의 비밀을 함께 생성
key agreement 임시 ECDHE 키 양쪽이 비밀을 전송하지 않고 같은 shared secret을 계산한다. 대칭 트래픽 키 공유 비밀에서 파생한 키가 AEAD 레코드의 내용과 변조를 보호한다.
- 임시 ECDHE 키
양쪽이 비밀을 전송하지 않고 같은 shared secret을 계산한다.
- 대칭 트래픽 키
공유 비밀에서 파생한 키가 AEAD 레코드의 내용과 변조를 보호한다.
| 기술 | 주된 역할 | 설명 |
|---|---|---|
| RSA-PSS | 디지털 서명 | 인증서 체인이나 핸드셰이크 서명에 사용 |
| ECDSA | 디지털 서명 | 작은 키로 효율적인 서명/검증 |
| Ed25519 | 디지털 서명 | SSH 등에서 널리 쓰이며 TLS에서도 지원 가능 |
| ECDHE | 임시 키 교환 | 전방 비밀성을 제공하는 TLS 핵심 방식 |
| RSA key transport | 레거시 키 운반 방식 | TLS 1.3에서는 제거, TLS 1.2에서도 비권장 |
공개키 암호를 이해할 때 가장 흔한 오해는 “공개키로 세션 키를 암호화해서 보내면 TLS가 끝난다”는 설명입니다.
과거 TLS 1.2에는 RSA key transport가 있었지만, 현대 TLS는 ECDHE 같은 임시 키 교환으로 공유 비밀을 만들고, 인증서는 그 키 교환이 진짜 서버와 이루어졌는지 확인하는 데 사용합니다.
TLS의 하이브리드 구조
TLS는 하나의 암호 기법만 쓰지 않습니다.
핸드셰이크에서는 공개키 기반 인증과 키 교환으로 안전하게 공유 비밀을 만들고, 연결이 성립한 뒤에는 빠른 대칭키 암호로 레코드를 보호합니다.
클라이언트와 서버는 먼저 알고리즘과 임시 키를 교환하고 신원을 검증한다. Finished가 통과한 뒤부터 HTTP 데이터를 대칭키로 보호한다.
- 선택지를 제시
ClientHello 선택지를 제시 지원 버전, cipher suite, 임시 key share를 서버에 보낸다.
- 선택과 신원 증명
ServerHello 선택과 신원 증명 서버가 설정을 고르고 인증서와 서명으로 자신의 키 소유를 보인다.
- 같은 비밀을 확인
Finished 같은 비밀을 확인 양쪽이 트래픽 키를 파생하고 핸드셰이크 기록의 무결성을 확인한다.
- AEAD 레코드 보호
Application Data AEAD 레코드 보호 HTTP 요청과 응답을 빠른 대칭키로 암호화하고 변조를 검증한다.
이 구조를 하이브리드 암호화라고 부를 수 있습니다.
공개키 기술은 신원 확인과 키 합의에 강하고, 대칭키 암호는 대량 데이터 보호에 빠릅니다.
TLS는 둘의 장점을 시간순으로 나누어 씁니다.
해시 함수와 MAC
해시 함수(Hash Function)는 임의 길이 데이터를 고정 길이의 값으로 변환합니다.
단, 해시는 “고유한 값”이 아닙니다.
출력 길이가 고정되어 있으므로 이론적으로 충돌은 존재합니다.
좋은 암호학적 해시는 충돌을 찾기 어렵고, 입력이 조금만 바뀌어도 출력이 크게 달라지며, 출력만 보고 입력을 역산하기 어렵도록 설계됩니다.
둘 다 입력이 바뀌면 결과가 달라지지만, Hash는 누구나 다시 계산할 수 있다. HMAC만 비밀 키를 아는 상대가 만든 값인지 확인한다.
- 1 · Hash메시지를 지문으로 변환
· Hash 메시지를 지문으로 변환 message → digest 같은 입력은 같은 고정 길이 결과를 만든다.
- 2 · 한계공격자도 다시 계산
· 한계 공격자도 다시 계산 메시지를 바꾸고 새 Hash를 붙일 수 있어 출처나 비밀 소유를 증명하지 못한다.
- 3 · HMAC비밀 키를 입력에 결합
· HMAC 비밀 키를 입력에 결합 key + message → tag 공유 키가 없으면 유효한 tag를 만들기 어렵다.
- 4 · Verify받은 tag를 안전하게 비교
· Verify 받은 tag를 안전하게 비교 같은 키로 계산한 결과와 비교해 메시지 변경과 키 소유 여부를 함께 판정한다.
| 알고리즘 | 출력 길이 | 현재 실무 판단 |
|---|---|---|
| MD5 | 128비트 | 충돌 공격 때문에 보안 용도로 사용 금지 |
| SHA-1 | 160비트 | 충돌 공격 때문에 사용 중단 방향 |
| SHA-256 | 256비트 | 널리 쓰이는 SHA-2 계열 해시 |
| SHA-384 | 384비트 | TLS cipher suite에서도 사용 |
| SHA-512 | 512비트 | SHA-2 계열의 더 긴 출력 |
| SHA-3 | 다양 | SHA-2와 다른 구조의 표준 해시 |
해시만으로는 “누가 만든 값인지”를 증명하지 못합니다.
그래서 메시지 무결성과 인증이 필요할 때는 비밀 키를 함께 쓰는 HMAC 같은 MAC(Message Authentication Code)을 사용합니다.
import hashlib
import hmac
import secrets
def hash_demo():
"""SHA-256 해시 계산"""
message = "Hello, TLS!"
hash_value = hashlib.sha256(message.encode()).hexdigest()
print(f"메시지: {message}")
print(f"SHA-256: {hash_value}")
message2 = "Hello, TLS?"
hash_value2 = hashlib.sha256(message2.encode()).hexdigest()
print(f"메시지 변경 후 SHA-256: {hash_value2}")
def hmac_demo():
"""HMAC으로 메시지 무결성과 공유 비밀 소유를 함께 확인"""
key = secrets.token_bytes(32)
message = b"transfer: 1000 to account 1234"
mac = hmac.new(key, message, hashlib.sha256).digest()
print(hmac.compare_digest(mac, hmac.new(key, message, hashlib.sha256).digest()))
tampered = b"transfer: 9999 to account 5678"
print(hmac.compare_digest(mac, hmac.new(key, tampered, hashlib.sha256).digest()))
hash_demo()
hmac_demo()디지털 서명의 원리
디지털 서명(Digital Signature)은 개인키로 서명하고 공개키로 검증하는 기술입니다.
“해시값을 개인키로 암호화한다”는 설명은 RSA 일부 형태를 지나치게 단순화한 표현입니다.
더 정확히는 서명 알고리즘이 메시지 또는 메시지 해시와 개인키를 입력으로 받아 서명값을 만들고, 검증자는 공개키로 그 서명이 해당 메시지에 대해 유효한지 확인합니다.
디지털 서명은 해시를 복호화하는 동작이 아니라, 메시지와 개인키로 만든 값을 원본 데이터와 공개키로 검증하는 절차입니다.
- ordered steps서명과 검증 단계
ordered steps 1 Data fixed 문서, 인증서 필드, payload처럼 바뀌면 안 되는 데이터를 정한다. 2 Sign 개인키 소유자가 data에 대해 signature를 만든다. 3 Send data와 signature, 공개키로 이어지는 인증 정보를 함께 전달한다. 4 Verify 공개키, data, signature를 넣어 유효 또는 무효를 판정한다.
- Data fixed
문서, 인증서 필드, payload처럼 바뀌면 안 되는 데이터를 정한다.
- Sign
개인키 소유자가 data에 대해 signature를 만든다.
- Send
data와 signature, 공개키로 이어지는 인증 정보를 함께 전달한다.
- Verify
공개키, data, signature를 넣어 유효 또는 무효를 판정한다.
- checkpointsTLS에서의 위치
checkpoints CertificateVerify 서버는 핸드셰이크 transcript에 서명해 개인키 소유를 보인다. 인증서 브라우저는 공개키가 접속한 이름의 인증서 체인에 속하는지 확인한다. 대칭키와 구분 서명은 인증과 무결성 증명이고, 실제 데이터 보호는 AEAD 대칭키가 맡는다.
- CertificateVerify
서버는 핸드셰이크 transcript에 서명해 개인키 소유를 보인다.
- 인증서
브라우저는 공개키가 접속한 이름의 인증서 체인에 속하는지 확인한다.
- 대칭키와 구분
서명은 인증과 무결성 증명이고, 실제 데이터 보호는 AEAD 대칭키가 맡는다.
| 검사 | 통과 의미 | 실패 신호 |
|---|---|---|
| 무결성 | 서명 대상 데이터가 바뀌지 않았다 | 한 글자만 바뀌어도 검증 실패 |
| 출처 | 짝이 되는 개인키로 만든 서명이다 | 다른 키로 만든 서명은 무효 |
| 맥락 | 인증서 체인과 용도가 맞다 | 신뢰할 수 없는 키면 연결 차단 |
TLS 인증서에서는 이 메커니즘이 핵심적으로 쓰입니다.
CA가 인증서 내용에 서명하고, 브라우저는 신뢰 저장소의 CA 공개키로 인증서 체인을 검증합니다.
이후 TLS 핸드셰이크에서는 서버가 인증서의 개인키를 실제로 소유하고 있음을 별도 서명으로 증명합니다.
면접 포인트
| 질문 | 핵심 답변 |
|---|---|
| 대칭키 vs 공개키? | 대칭키는 같은 비밀 키로 빠르게 데이터 보호, 공개키는 인증·서명·키 교환에 적합 |
| TLS에서 둘 다 쓰는 이유? | 핸드셰이크로 키를 합의하고, 이후 대칭키 AEAD로 데이터를 빠르게 보호 |
| 해시와 HMAC 차이? | 해시는 공개 계산 가능, HMAC은 비밀 키를 알아야 같은 값을 만들 수 있음 |
| 디지털 서명 원리? | 개인키로 서명하고 공개키로 검증해 무결성, 출처, 부인 방지를 제공 |
마지막으로 TLS가 대칭키, 공개키, 해시/MAC, 서명을 어떻게 나누어 쓰는지 운영 점검 기준과 함께 정리합니다.
“공개키로 HTTP를 암호화한다”가 아니라 handshake가 신원·공유 비밀·기록 무결성을 묶고 record layer가 파생된 키를 쓰는 구조다.
- 1. ClientHello
ClientHello 지원 버전·AEAD/HKDF 조합과 임시 key share를 제안한다.
- 2. ServerHello
ServerHello 선택값과 key share로 양쪽이 같은 handshake secret을 만든다.
- 3. CertificateVerify
CertificateVerify 인증서 경로·서비스 이름을 검증하고 서명으로 개인키 보유와 transcript를 확인한다.
- 4. Finished
Finished 파생 키로 전체 handshake 기록이 변조되지 않았음을 상호 확인한다.
- 5. Application records
Application records 방향별 traffic key와 nonce로 각 record를 AEAD 보호한다.
- 인증서 + 서명
신뢰 경로, 서비스 신원, handshake 출처를 증명한다. 본문 암호가 아니다.
- (EC)DHE
비밀을 전송하지 않고 공유 비밀에 도달하며 전방 비밀성을 제공한다.
- HKDF + transcript
handshake·application, client·server 키를 목적별로 분리한다.
- AEAD
record의 기밀성과 무결성을 함께 제공하고 변조를 탐지한다.
다음 절에서는 이 암호화 기법들이 실제로 어떻게 조합되어 TLS 핸드셰이크를 이루는지 살펴보겠습니다.