작성일 :

안전한 연결이 필요한 이유

Part 1에서 대칭키 암호, 비대칭키 암호, 해시 함수 등 암호화의 수학적 기초를 살펴보았습니다. 그렇다면 이것들을 어떻게 조합하여 실제 안전한 통신을 구현할 수 있을까요?


인터넷에서 가장 널리 사용되는 보안 프로토콜인 TLS(Transport Layer Security)가 그 답을 제시합니다. HTTPS의 “S”가 바로 TLS를 의미합니다.


TLS가 해결해야 하는 문제:

  1. 키 교환: 처음 만난 두 당사자가 어떻게 공유 비밀을 만드는가
  2. 서버 인증: 내가 접속한 서버가 진짜 그 서버인지 어떻게 확인하는가
  3. 데이터 보호: 교환된 키로 어떻게 데이터를 암호화하고 무결성을 보장하는가

TLS의 역사

SSL(Secure Sockets Layer)은 1994년 Netscape가 개발한 보안 프로토콜입니다. 최초의 공개 버전인 SSL 2.0에는 심각한 취약점이 있었고, 이후 1996년에 발표된 SSL 3.0이 널리 사용되었습니다.


1999년에는 IETF가 SSL 3.0을 기반으로 TLS 1.0을 표준화했습니다.

  • TLS 1.0 (1999): SSL 3.0과 거의 동일
  • TLS 1.1 (2006): CBC 공격 완화
  • TLS 1.2 (2008): SHA-256, AEAD 지원
  • TLS 1.3 (2018): 대폭 개선, 레거시 제거


현재 TLS 1.2와 1.3만 안전한 것으로 간주되며, TLS 1.0/1.1과 SSL은 더 이상 사용해서는 안 됩니다.


TLS 1.2 핸드셰이크

TLS 연결은 핸드셰이크로 시작되며, 이 과정에서 암호화 파라미터를 협상하고 키를 교환합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Client                                 Server
   │                                      │
   │ ──────── ClientHello ──────────────► │
   │                                      │
   │ ◄─────── ServerHello ─────────────── │
   │ ◄─────── Certificate ─────────────── │
   │ ◄─────── ServerKeyExchange ───────── │
   │ ◄─────── ServerHelloDone ─────────── │
   │                                      │
   │ ──────── ClientKeyExchange ────────► │
   │ ──────── ChangeCipherSpec ─────────► │
   │ ──────── Finished ─────────────────► │
   │                                      │
   │ ◄─────── ChangeCipherSpec ────────── │
   │ ◄─────── Finished ────────────────── │
   │                                      │
   │ ════════ 암호화된 통신 ════════════ │


1. ClientHello

클라이언트가 지원하는 것들을 알려줍니다:

  • TLS 버전
  • 지원하는 암호 스위트 목록
  • 무작위 값 (client random)
  • 지원하는 압축 방법


2. ServerHello

서버가 선택한 것들을 알려줍니다:

  • 사용할 TLS 버전
  • 선택한 암호 스위트
  • 무작위 값 (server random)


3. Certificate

서버의 인증서를 전송하며, 이 인증서에는 서버의 공개키가 포함되어 있습니다.


4. ServerKeyExchange

키 교환에 필요한 추가 파라미터를 전송하는데, DHE나 ECDHE 사용 시 서버의 임시 공개키가 여기에 포함됩니다.


5. ClientKeyExchange

클라이언트의 키 교환 데이터로, ECDHE의 경우 클라이언트의 임시 공개키가 해당됩니다.


6. 세션 키 파생

양쪽이 공유한 정보를 바탕으로 Pre-Master Secret을 생성하고, 이를 통해 Master Secret과 최종 세션 키를 파생합니다.


파생된 세션 키들:

  • client_write_key: 클라이언트 → 서버 암호화
  • server_write_key: 서버 → 클라이언트 암호화
  • client_write_MAC_key: 클라이언트 → 서버 MAC
  • server_write_MAC_key: 서버 → 클라이언트 MAC


7. Finished

지금까지의 모든 핸드셰이크 메시지의 해시를 암호화하여 전송하고, 상대방도 같은 값을 계산하여 비교합니다. 이 값이 일치하면 키 교환이 성공적으로 완료된 것입니다.


TLS 1.2의 문제점

TLS 1.2 핸드셰이크는 2-RTT(Round Trip Time)가 필요합니다(ClientHello → ServerHello…Finished → ClientFinished → 데이터). 100ms 지연의 네트워크에서 핸드셰이크만 200ms가 소요되고, 모바일 네트워크에서는 이보다 더 오래 걸릴 수 있습니다.


또한 여러 레거시 알고리즘이 여전히 허용되어 보안상 우려가 있었습니다:

  • RSA 키 교환 (전방향 비밀성 없음)
  • CBC 모드 (패딩 오라클 공격 가능)
  • 약한 해시 함수 (SHA-1)

TLS 1.3: 단순화와 강화

이러한 문제점들을 해결하기 위해 2018년에 발표된 TLS 1.3은 대폭 개선되었습니다.


핸드셰이크가 1-RTT로 단축

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Client                                 Server
   │                                      │
   │ ──────── ClientHello ──────────────► │
   │          + KeyShare                  │
   │                                      │
   │ ◄─────── ServerHello ─────────────── │
   │          + KeyShare                  │
   │ ◄─────── {EncryptedExtensions} ───── │
   │ ◄─────── {Certificate} ───────────── │
   │ ◄─────── {CertificateVerify} ─────── │
   │ ◄─────── {Finished} ───────────────── │
   │                                      │
   │ ──────── {Finished} ─────────────► │
   │                                      │
   │ ════════ 암호화된 통신 ════════════ │

{ } = 암호화된 메시지


클라이언트가 첫 메시지에 KeyShare(임시 공개키)를 포함하므로, 서버가 응답할 때 이미 암호화된 데이터를 보낼 수 있게 됩니다.


0-RTT 재개

이전에 연결했던 서버라면 0-RTT로 데이터를 보낼 수 있어, 첫 메시지에 암호화된 애플리케이션 데이터를 포함할 수 있습니다. 단, 리플레이 공격 위험이 있으므로 GET 요청처럼 멱등성(idempotent)이 있는 요청에만 사용해야 합니다.


레거시 제거

TLS 1.3에서 제거된 것들:

  • RSA 키 교환 (전방향 비밀성 없음)
  • CBC 모드 (패딩 오라클 공격)
  • RC4, DES, 3DES
  • SHA-1
  • 압축 (CRIME 공격)
  • 재협상


남은 암호 스위트:

  • TLS_AES_128_GCM_SHA256
  • TLS_AES_256_GCM_SHA384
  • TLS_CHACHA20_POLY1305_SHA256


이 암호 스위트들은 모두 AEAD(인증된 암호화)를 사용하며, 전방향 비밀성(ECDHE 또는 DHE)이 필수로 요구됩니다.


인증서: 신뢰의 기반

그렇다면 TLS에서 서버의 공개키를 어떻게 신뢰할 수 있을까요?


중간자 공격(Man-in-the-Middle, MITM)

이 문제를 이해하려면 먼저 중간자 공격을 알아야 합니다. 공격자가 클라이언트와 서버 사이에 끼어들어 양쪽을 속이는 공격입니다.

1
2
3
4
Client ◄──► Attacker ◄──► Server

Client는 Attacker가 Server인 줄 암
Server는 Attacker가 Client인 줄 암


공격자가 자신의 공개키를 서버의 것이라고 속이면 클라이언트는 공격자의 키로 암호화하게 됩니다. 공격자는 이를 복호화한 뒤 진짜 서버의 키로 다시 암호화해서 전달하므로, 양쪽 모두 공격 사실을 알아채지 못합니다.


따라서 이를 방지하려면 서버의 공개키가 진짜 그 서버의 것임을 확인할 방법이 필요합니다.


PKI: 공개키 기반 구조

PKI(Public Key Infrastructure)는 공개키의 소유권을 증명하는 체계입니다. 핵심 아이디어는 신뢰할 수 있는 제3자인 인증 기관(CA, Certificate Authority)이 “이 공개키는 이 주체의 것”이라고 서명하는 방식입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
웹사이트 운영자:
  1. 키 쌍 생성 (공개키, 개인키)
  2. 인증 요청서(CSR) 생성
  3. CA에 제출

CA:
  1. 신원 확인
  2. 인증서 발급 (공개키 + 신원 정보 + CA의 서명)

사용자:
  1. 웹사이트의 인증서 수신
  2. CA의 공개키로 서명 검증
  3. 유효하면 웹사이트의 공개키를 신뢰

X.509 인증서 구조

인증서의 표준 형식은 X.509이며, 주요 필드는 다음과 같습니다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Version: 3 (현재 버전)
Serial Number: 인증서 고유 번호
Signature Algorithm: CA가 서명에 사용한 알고리즘
Issuer: 발급자 (CA) 정보
Validity:
  Not Before: 유효 시작일
  Not After: 유효 종료일
Subject: 인증서 주체 정보
Subject Public Key Info:
  Algorithm: 공개키 알고리즘
  Public Key: 실제 공개키
Extensions:
  Subject Alternative Name: 대체 도메인 이름
  Key Usage: 키 용도
  ...
Signature: CA의 서명


특히 Subject Alternative Name(SAN)이 중요한데, 하나의 인증서로 여러 도메인을 커버할 수 있게 해줍니다:

1
2
3
example.com
www.example.com
api.example.com

인증서 체인

그렇다면 CA의 공개키는 어떻게 신뢰할 수 있을까요? 상위 CA가 서명하는 방식으로 신뢰 체계를 형성합니다.


인증서 체인(Certificate Chain)은 다음과 같은 구조를 가집니다:

1
2
3
4
5
6
7
루트 CA 인증서
     │ (서명)
     ▼
중간 CA 인증서
     │ (서명)
     ▼
서버 인증서 (End-Entity)


  • 루트 CA: 자기 자신을 서명 (자체 서명, self-signed)
  • 중간 CA: 루트 CA가 서명
  • 서버 인증서: 중간 CA가 서명


그렇다면 루트 CA 인증서는 어떻게 신뢰할 수 있을까요? 루트 CA 인증서는 운영체제와 브라우저에 미리 설치되어 있으며, 이를 신뢰 저장소(Trust Store)라고 합니다.


Windows, macOS, iOS, Android, Firefox 등은 각각 자체 신뢰 저장소를 관리하며, 약 100~200개의 루트 CA가 포함되어 있습니다.


인증서 검증 과정

브라우저가 인증서를 검증하는 과정:


1. 체인 구축

서버가 보낸 인증서들로 루트까지 체인을 만듭니다.


2. 서명 검증

각 인증서의 서명이 상위 인증서의 공개키로 유효한지 확인합니다.


3. 유효 기간 확인

현재 시간이 Not Before와 Not After 사이인지 확인합니다.


4. 폐기 여부 확인

인증서가 폐기되지 않았는지 확인합니다.

  • CRL(Certificate Revocation List): CA가 발행하는 폐기 목록
  • OCSP(Online Certificate Status Protocol): 실시간 상태 확인


5. 도메인 일치 확인

인증서의 Subject 또는 SAN이 접속하려는 도메인과 일치하는지 확인합니다.


6. 신뢰 루트 확인

체인의 최상위가 신뢰 저장소에 있는 루트 CA인지 확인합니다.


인증서 투명성 (Certificate Transparency)

만약 CA가 악의적이거나 실수로 잘못된 인증서를 발급하면 어떻게 될까요?


2011년에 DigiNotar CA가 해킹당하는 사건이 발생했습니다. 공격자가 google.com에 대한 인증서를 발급받아 이란에서 Gmail 사용자를 대상으로 MITM 공격에 사용했던 것입니다.


Certificate Transparency(CT)는 이러한 문제를 방지하기 위한 시스템입니다. 모든 인증서 발급을 공개 로그에 기록하여 누구나 로그를 모니터링할 수 있게 하고, 도메인 소유자가 자신의 도메인에 대한 모든 인증서를 확인할 수 있도록 합니다.


1
2
3
4
5
6
7
8
9
10
CA가 인증서 발급
     │
     ▼
CT 로그에 제출
     │
     ▼
SCT(Signed Certificate Timestamp) 반환
     │
     ▼
인증서에 SCT 포함


Chrome은 2018년부터 CT가 없는 인증서를 신뢰하지 않습니다.


Let’s Encrypt: 무료 자동화 인증서

전통적으로 인증서는 비용이 높고(연간 수십~수백 달러), 수동으로 발급받아야 했으며(서류 제출, 이메일 검증), 1~2년의 유효 기간을 가졌습니다.


Let’s Encrypt는 2016년에 시작된 무료 CA로, 이러한 장벽을 크게 낮추었습니다. 주요 특징은 다음과 같습니다:

  • 무료: 비용 없음
  • 자동화: ACME 프로토콜로 자동 발급/갱신
  • 짧은 유효 기간: 90일 (자동 갱신 권장)
  • DV 인증서만: 도메인 소유권만 확인


ACME(Automated Certificate Management Environment)는 도메인 소유권을 자동으로 증명하는 프로토콜입니다.

1
2
3
4
5
1. 클라이언트가 Let's Encrypt에 도메인 인증 요청
2. Let's Encrypt가 챌린지 제시 (HTTP 또는 DNS)
3. 클라이언트가 챌린지 완료 (특정 파일 배치 또는 DNS 레코드 생성)
4. Let's Encrypt가 검증
5. 인증서 발급


Let’s Encrypt 덕분에 HTTPS 도입 비용이 크게 낮아졌습니다.


인증서의 종류

DV(Domain Validation)

  • 도메인 소유권만 확인
  • 가장 저렴하고 빠름
  • Let’s Encrypt가 제공하는 것


OV(Organization Validation)

  • 조직의 실제 존재 확인
  • 회사 등록 서류 검토
  • 인증서에 조직 이름 포함


EV(Extended Validation)

  • 가장 엄격한 검증
  • 법적 실체, 물리적 존재, 운영 상태 확인
  • 예전에는 브라우저에서 녹색 주소창으로 표시 (현재는 대부분 폐지)


기술적 보안 수준은 모두 동일하며, 차이는 “누가 이 도메인을 운영하는가”에 대한 신뢰 수준에 있습니다.


HSTS: 다운그레이드 방지

사용자가 http://example.com으로 접속하면 서버가 https://로 리다이렉트합니다. 하지만 첫 번째 HTTP 요청은 암호화되지 않았으므로, 공격자가 리다이렉트를 가로채고 HTTP로 유지할 수 있습니다. 이것이 SSL Stripping 공격입니다.


HSTS(HTTP Strict Transport Security)는 이러한 공격을 방지합니다.


서버가 응답 헤더에 다음과 같이 포함하면:

1
Strict-Transport-Security: max-age=31536000; includeSubDomains


브라우저는 이 도메인에 대해 지정된 기간 동안 HTTP 요청을 자동으로 HTTPS로 변환하고, 인증서 오류 시에는 예외를 허용하지 않고 연결을 거부합니다.


HSTS Preload는 한 단계 더 강력한 보호를 제공합니다. 브라우저에 미리 HSTS 도메인 목록을 포함하여 첫 방문부터 HTTPS를 강제합니다.


TLS가 보호하는 것과 보호하지 않는 것

TLS가 보호하는 것:

  • 데이터의 기밀성 (도청 방지)
  • 데이터의 무결성 (변조 방지)
  • 서버 인증 (가짜 서버 방지)


TLS가 보호하지 않는 것:

  • 메타데이터 (접속한 IP, 시간, 데이터 크기)
  • SNI(Server Name Indication) - 어떤 도메인에 접속하는지 노출
  • 클라이언트가 누구인지 (기본적으로)


SNI는 여러 도메인이 같은 IP를 공유할 때 필요합니다. 클라이언트가 “나는 example.com에 접속하려 한다”고 평문으로 알려주면 서버가 올바른 인증서를 선택할 수 있게 됩니다.


Encrypted Client Hello(ECH)는 SNI마저 암호화하려는 시도로, TLS 1.3의 확장으로 개발 중입니다.


Part 3에서는 네트워크 계층별 공격과 방어 메커니즘을 살펴보겠습니다.


관련 글

Tags: HTTPS, TLS, 네트워크, 보안, 인증서

Categories: ,