본문 바로가기
카테고리 없음

🔒 TLS/SSL에 대하여

by SuldenLion 2026. 2. 18.
반응형

TLS/SSL 완전 가이드: HTTPS를 만드는 암호화 프로토콜의 모든 것

 

자물쇠 하나가 인터넷 상거래를 가능하게 만들었다

1990년대 중반, 인터넷이 대중화되기 시작했을 때 심각한 문제가 있었습니다. 모든 통신이 평문(Plain Text)으로 전송되었기 때문에, 누구나 중간에서 패킷을 가로채 읽을 수 있었습니다.

신용카드 번호를 입력하면? → 해커가 그대로 볼 수 있었습니다.
비밀번호를 전송하면? → 중간에서 탈취 가능했습니다.
개인정보를 보내면? → 모두에게 공개되는 것과 같았습니다.

이런 상황에서 인터넷 쇼핑, 온라인 뱅킹, 이메일이 가능할까요? 불가능했습니다.

그래서 1994년, 넷스케이프(Netscape)는 SSL(Secure Sockets Layer) 을 개발했습니다. 이후 SSL은 TLS(Transport Layer Security) 로 발전했고, 2018년에는 TLS 1.3이 발표되었습니다.

현재 전 세계 웹사이트의 90% 이상이 HTTPS(HTTP + TLS)를 사용합니다. 브라우저 주소창의 작은 자물쇠 아이콘 — 그것이 TLS가 작동하고 있다는 신호입니다.

이 글에서는 TLS/SSL이 무엇인지, 어떻게 작동하는지, TLS 1.3의 개선사항, 그리고 개발자가 HTTPS를 적용하는 방법까지 완전히 정리하겠습니다.

 

SSL과 TLS — 무엇이 다른가?

SSL의 탄생과 역사

SSL(Secure Sockets Layer) 은 1994년 넷스케이프가 처음 개발했습니다.

  • SSL 1.0: 공개되지 않음 (보안 결함으로 폐기)
  • SSL 2.0 (1995): 최초 공개 버전, 하지만 곧 취약점 발견
  • SSL 3.0 (1996): 대폭 개선되어 널리 사용됨

TLS의 등장

1999년, IETF(Internet Engineering Task Force)가 SSL 3.0을 기반으로 TLS 1.0을 표준화했습니다. SSL에서 TLS로 이름이 바뀐 이유는 표준화 기구가 넷스케이프에서 IETF로 이동했기 때문입니다.

TLS 버전 역사:

버전
발표 연도 주요 특징 현재 상태
TLS 1.0 1999 SSL 3.0 기반 표준화 ❌ 사용 금지 (2020)
TLS 1.1 2006 CBC 공격 방어 ❌ 사용 금지 (2020)
TLS 1.2 2008 SHA-256 지원, AEAD 암호 ✅ 현재 사용 중
TLS 1.3 2018 1-RTT 핸드셰이크, 취약 암호 제거 ✅ 권장

"SSL/TLS"라고 부르는 이유

기술적으로는 TLS가 정확하지만, SSL이라는 용어가 너무 유명해져서 두 용어를 함께 사용합니다. "SSL 인증서"라고 말하지만 실제로는 TLS를 사용하는 것입니다.

핵심:

SSL은 레거시, TLS가 현대 표준. 하지만 사람들은 여전히 "SSL"이라고 부른다.

 

 

TLS/SSL의 3가지 보안 목표

TLS는 인터넷 통신에서 다음 3가지를 보장합니다:

① 기밀성 (Confidentiality) — 암호화

통신 내용을 제3자가 읽을 수 없도록 암호화합니다.

평문: "내 카드번호는 1234-5678-9012-3456"
암호화: "A7B3C9D2E4F1G8H5..."

중간에서 패킷을 가로채도 암호화된 데이터만 보입니다.

 

② 무결성 (Integrity) — 변조 방지

전송 중 데이터가 변조되지 않았음을 보장합니다.

HMAC(Hash-based Message Authentication Code) 을 사용하여 각 패킷의 해시값을 계산하고, 수신 측에서 재계산하여 비교합니다.

 
원본 데이터: "송금 1,000원"
해시값: abc123

[중간자가 변조 시도]
변조 데이터: "송금 1,000,000원"
해시값: xyz789  ← 원본과 다름! 거부됨

 

 

③ 인증 (Authentication) — 신원 확인

통신 상대방이 진짜 본인인지 확인합니다.

디지털 인증서를 통해 "이 서버가 정말 naver.com인가?"를 검증합니다. 이를 통해 피싱 사이트를 걸러낼 수 있습니다.

 

TLS의 핵심 원리: 하이브리드 암호화

TLS는 비대칭 암호화대칭 암호화를 모두 사용하는 하이브리드 시스템입니다.

비대칭 암호화 (Asymmetric Encryption)

공개 키(Public Key)개인 키(Private Key) 라는 한 쌍의 키를 사용합니다.

특징:

  • 공개 키로 암호화 → 개인 키로만 복호화 가능
  • 개인 키로 서명 → 공개 키로 검증 가능
  • 안전하지만 느림 (RSA, ECDSA 등)

예시:

Alice가 Bob에게 메시지 전송:
1. Alice가 Bob의 공개 키로 메시지 암호화
2. Bob만 자신의 개인 키로 복호화 가능

 

 

대칭 암호화 (Symmetric Encryption)

단일 키(Shared Key) 를 양쪽이 공유하여 사용합니다.

특징:

  • 같은 키로 암호화 및 복호화
  • 빠르지만 키 공유가 위험 (AES, ChaCha20 등)

 

왜 둘 다 사용하는가?

문제:

  • 비대칭 암호화: 안전하지만 너무 느림 (대칭보다 100~1000배 느림)
  • 대칭 암호화: 빠르지만 키를 안전하게 공유하기 어려움

해결책 (TLS의 전략):

  1. 핸드셰이크 단계: 비대칭 암호화로 세션 키(대칭 키)를 안전하게 교환
  2. 데이터 전송 단계: 세션 키(대칭 암호화)로 빠르게 통신
 
[비대칭 암호화 - 느리지만 안전]
→ 세션 키 교환

[대칭 암호화 - 빠름]
→ 실제 데이터 전송

 

 

TLS 핸드셰이크: 안전한 연결 수립 과정

TLS 핸드셰이크는 클라이언트와 서버가 암호화 통신을 시작하기 전에 세션 키를 교환하는 과정입니다.

TLS 1.2 핸드셰이크 (2-RTT)

RTT(Round-Trip Time): 클라이언트 → 서버 → 클라이언트 한 왕복

Client                                Server

1. ClientHello -------->
   (지원 암호 스위트, 랜덤값)

                         <-------- 2. ServerHello
                                   (선택된 암호 스위트, 랜덤값)
                                   Certificate
                                   (서버 인증서)
                                   ServerKeyExchange
                                   (키 교환 정보)
                                   ServerHelloDone

3. ClientKeyExchange ---->
   (암호화된 Pre-Master Secret)
   ChangeCipherSpec
   Finished

                         <-------- 4. ChangeCipherSpec
                                   Finished

[암호화된 데이터 전송 시작]

단계별 설명:

  1. ClientHello: 클라이언트가 지원하는 암호화 방식 목록 전송
  2. ServerHello: 서버가 암호화 방식 선택, 인증서 전송
  3. Key Exchange: Pre-Master Secret 교환, 양측이 Master Secret 생성
  4. Finished: 핸드셰이크 완료, 세션 키로 통신 시작

총 왕복: 2-RTT (약 100~200ms)

 

TLS 1.3 핸드셰이크 (1-RTT) — 50% 더 빠름!

TLS 1.3은 핸드셰이크를 1-RTT로 단축했습니다.

Client                                Server

1. ClientHello -------->
   (지원 암호 + 키 공유 정보 미리 전송!)

                         <-------- 2. ServerHello
                                   (선택 암호 + 키 공유)
                                   Certificate
                                   Finished
                                   [암호화된 애플리케이션 데이터]

3. Finished ----------->
   [암호화된 애플리케이션 데이터]

 

차이점:

항목 TLS 1.2 TLS 1.3
RTT 2회 1회
지연 시간 ~200ms ~100ms
키 교환 2단계 분리 1단계 통합

핵심 개선:
클라이언트가 첫 번째 메시지에서 키 교환 정보를 미리 포함시켜, 서버가 즉시 세션 키를 생성하고 암호화된 응답을 보낼 수 있습니다.

 

TLS 1.3의 0-RTT 재개 (0-RTT Resumption)

이전에 연결했던 서버에 재접속할 때, 핸드셰이크 없이 즉시 데이터 전송이 가능합니다!

[첫 방문]
Client → Server: 1-RTT 핸드셰이크
→ 양측이 PSK (Pre-Shared Key) 저장

[재방문]
Client → Server: PSK + 암호화된 HTTP 요청 (0-RTT!)
→ 서버가 즉시 응답

총 지연: HTTP와 동일!

주의: 0-RTT는 재전송 공격(Replay Attack)에 취약할 수 있으므로, 멱등성(Idempotent)이 보장되는 요청(GET 등)에만 사용해야 합니다.

 

디지털 인증서와 CA (Certificate Authority)

인증서가 필요한 이유

공개 키를 받았을 때, "이 공개 키가 정말 naver.com의 것인가?" 를 어떻게 확인할까요?

문제 시나리오:

사용자 → [해커의 가짜 naver.com] → 해커의 공개 키

사용자는 해커의 공개 키로 비밀번호를 암호화하여 전송 → 해커가 복호화 → 비밀번호 탈취!

해결책: 신뢰할 수 있는 제3자(CA)가 "이 공개 키는 진짜 naver.com의 것입니다" 라고 보증하는 디지털 인증서를 발급합니다.

 

인증서의 구조

json
{
  "version": "3",
  "serialNumber": "0A1B2C3D...",
  "issuer": "DigiCert Inc",
  "validity": {
    "notBefore": "2024-01-01",
    "notAfter": "2025-12-31"
  },
  "subject": "naver.com",
  "subjectPublicKeyInfo": {
    "algorithm": "RSA",
    "publicKey": "MIIBIjANBg..."
  },
  "signature": "CA의 개인 키로 서명된 값"
}

핵심 필드:

  • Issuer: 인증서를 발급한 CA
  • Subject: 인증서의 소유자 (도메인)
  • Public Key: 서버의 공개 키
  • Signature: CA가 개인 키로 서명한 값

 

CA 신뢰 체인 (Chain of Trust)

브라우저와 운영체제는 루트 CA의 인증서를 미리 저장하고 있습니다.

[루트 CA] (브라우저에 내장)
   ↓ 서명
[중간 CA]
   ↓ 서명
[최종 인증서 - naver.com]

검증 과정:

  1. 서버가 naver.com 인증서 전송
  2. 브라우저가 중간 CA의 공개 키로 서명 검증
  3. 중간 CA 인증서를 루트 CA의 공개 키로 검증
  4. 루트 CA는 브라우저에 내장 → 신뢰 완료!

 

주요 CA 목록

CA
시장 점유율 특징
Let's Encrypt ~40% 무료, 자동화 (권장!)
DigiCert ~20% 유료, 엔터프라이즈
Sectigo ~15% 중소기업용
GoDaddy ~10% 호스팅 통합

 

 

TLS 1.3의 주요 개선사항

① 취약한 암호 알고리즘 제거

TLS 1.2에서 지원했던 오래되고 위험한 암호화 방식을 완전히 제거했습니다.

제거된 알고리즘:

  • RSA 키 교환: 순방향 비밀성(Forward Secrecy) 미제공
  • RC4, DES, 3DES: 약한 암호화
  • MD5, SHA-1: 충돌 공격 가능한 해시
  • 정적 DH: 키 재사용 위험

남은 안전한 알고리즘만:

  • 키 교환: Ephemeral Diffie-Hellman (DHE, ECDHE)
  • 암호화: AES-GCM, ChaCha20-Poly1305
  • 해시: SHA-256, SHA-384

 

② 순방향 비밀성 (Forward Secrecy)

문제 (TLS 1.2 RSA 방식):

서버의 개인 키가 해킹당하면, 과거의 모든 통신을 복호화할 수 있었습니다.

[해커가 과거 암호화 트래픽 저장]
→ [1년 후 서버 해킹, 개인 키 탈취]
→ [저장된 트래픽 전부 복호화!]

해결 (TLS 1.3 Ephemeral DH):

세션마다 일회용 키를 생성하므로, 서버 키가 유출되어도 과거 세션은 안전합니다.

 
각 세션 키 = 일회용 임시 키로 생성
→ 서버 개인 키 유출되어도 과거 세션 복호화 불가능

 

 

③ 암호화된 SNI (ESNI/ECH)

문제:

TLS 핸드셰이크의 SNI(Server Name Indication) 는 평문으로 전송되어, 어떤 도메인에 접속했는지 ISP가 알 수 있었습니다.

ClientHello:
  SNI: "wikileaks.org"  ← 평문! ISP가 볼 수 있음

해결 (Encrypted Client Hello, ECH):

TLS 1.3에서는 SNI도 암호화하여 전송합니다 (2024년 표준화).

ClientHello:
  SNI: [암호화됨]  ← ISP는 도메인을 알 수 없음

 

 

④ 성능 개선 요약

항목 TLS 1.2 TLS 1.3 개선율
핸드셰이크 RTT 2 1 50% 단축
재방문 시 1-RTT 0-RTT 100% 단축
암호 협상 복잡 (37개 옵션) 간소 (5개 옵션) 관리 용이

 

 

HTTPS 적용: 개발자 실전 가이드

방법 1: Let's Encrypt (무료, 권장)

Let's Encrypt는 무료 CA로, 자동 갱신을 지원합니다.

Certbot 사용 (Ubuntu/Nginx)

bash
# 1. Certbot 설치
sudo apt update
sudo apt install certbot python3-certbot-nginx

# 2. 인증서 발급 및 Nginx 자동 설정
sudo certbot --nginx -d example.com -d www.example.com

# 결과:
# - /etc/letsencrypt/live/example.com/fullchain.pem (인증서)
# - /etc/letsencrypt/live/example.com/privkey.pem (개인 키)
# - Nginx 설정 자동 수정

# 3. 자동 갱신 설정 (90일마다)
sudo certbot renew --dry-run

 

Nginx 설정 확인:

nginx
server {
    listen 443 ssl http2;
    server_name example.com;

    # Let's Encrypt 인증서
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # 보안 강화 설정
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # HSTS (HTTP Strict Transport Security)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    location / {
        proxy_pass http://localhost:3000;
    }
}

# HTTP → HTTPS 리다이렉트
server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

 

 

방법 2: Cloudflare (무료 + CDN)

Cloudflare는 무료 SSL/TLS + CDN + DDoS 방어를 제공합니다.

설정 단계

  1. Cloudflare 가입 및 도메인 추가
  2. DNS 네임서버를 Cloudflare로 변경
  3. SSL/TLS 설정 → Full (strict) 선택
  4. 완료! Cloudflare가 자동으로 인증서 발급 및 관리

장점:

  • 인증서 관리 불필요
  • 전 세계 CDN 엣지에서 TLS 종료
  • 무료 DDoS 방어
  • 자동 HTTP/2, HTTP/3 지원

 

방법 3: Node.js에서 직접 구현

javascript
// server.js
const https = require('https');
const fs = require('fs');
const express = require('express');

const app = express();

// SSL 인증서 로드
const options = {
    key: fs.readFileSync('/etc/letsencrypt/live/example.com/privkey.pem'),
    cert: fs.readFileSync('/etc/letsencrypt/live/example.com/fullchain.pem')
};

app.get('/', (req, res) => {
    res.send('Hello HTTPS!');
});

// HTTPS 서버 시작
https.createServer(options, app).listen(443, () => {
    console.log('HTTPS server running on port 443');
});

// HTTP → HTTPS 리다이렉트
const http = require('http');
http.createServer((req, res) => {
    res.writeHead(301, { Location: `https://${req.headers.host}${req.url}` });
    res.end();
}).listen(80);

 

 

TLS/SSL 보안 체크리스트

서버 설정

  • TLS 1.2 이상만 허용 (TLS 1.0, 1.1 비활성화)
  • TLS 1.3 활성화 (가능한 경우)
  • 강력한 암호 스위트만 사용 (ECDHE, AES-GCM 등)
  • 약한 암호 비활성화 (RC4, DES, MD5 등)
  • HSTS 헤더 설정 (브라우저가 항상 HTTPS 사용)
  • 인증서 자동 갱신 설정 (Let's Encrypt 90일)

 

인증서 관리

  • 유효 기간 확인 (만료 전 갱신)
  • 와일드카드 vs 멀티 도메인 선택
  • 중간 인증서 체인 포함 (fullchain.pem)
  • 개인 키 보안 (파일 권한 600, 암호화 저장)

 

모니터링

 

실전 테스트: SSL Labs

웹사이트의 TLS 설정을 A+ 등급으로 만들기:

bash
# 1. SSL Labs에서 테스트
https://www.ssllabs.com/ssltest/analyze.html?d=example.com

# 결과 예시:
# - Protocol Support: TLS 1.3 ✓
# - Cipher Strength: 256-bit ✓
# - Forward Secrecy: Yes ✓
# - HSTS: Enabled ✓
# Overall Rating: A+

A+ 등급 달성 조건:

  1. TLS 1.2, 1.3만 지원
  2. 강력한 암호 스위트
  3. HSTS 헤더
  4. 유효한 인증서 체인

 

마지막으로

TLS/SSL은 현대 인터넷의 근간입니다. 1990년대 넷스케이프의 SSL부터 2018년 TLS 1.3까지, 30년 가까운 발전을 거쳐 지금의 안전한 인터넷이 만들어졌습니다.

브라우저 주소창의 작은 자물쇠는 단순한 아이콘이 아닙니다. 그 뒤에는:

  • 비대칭 암호화로 안전하게 세션 키를 교환하고
  • 대칭 암호화로 빠르게 데이터를 전송하며
  • 디지털 인증서로 상대방의 신원을 확인하는

복잡하고 정교한 프로토콜이 작동하고 있습니다.

개발자가 할 일은 명확합니다:

① Let's Encrypt로 무료 HTTPS 적용
② TLS 1.2 이상만 허용
③ TLS 1.3 활성화 (권장)
④ HSTS 헤더 설정
⑤ 정기적인 보안 테스트

HTTPS는 더 이상 선택이 아닙니다. Google은 HTTP 사이트에 "안전하지 않음" 경고를 표시하고, 검색 순위에서 불이익을 줍니다. 법적 규제(GDPR, PCI DSS 등)도 암호화를 요구합니다.

지금 당장 Let's Encrypt를 설치하고, 30분 만에 HTTPS를 적용하세요:

 
bash
sudo certbot --nginx -d yourdomain.com

그 작은 자물쇠가 사용자의 신뢰를, 그리고 당신의 서비스를 지킵니다.

반응형

댓글