콘텐츠로 이동

HTTPS, TLS, HTTP/2 · HTTP/3

HTTP로 전송되는 데이터는 평문(plaintext)입니다. 중간에 누군가 패킷을 가로채면 요청 내용, API 키, 사용자 데이터가 그대로 노출됩니다. HTTPS는 HTTP에 TLS(Transport Layer Security) 암호화 레이어를 추가해 이 문제를 해결합니다.

HTTP: 클라이언트 ──평문──────────────── 서버
HTTPS: 클라이언트 ──암호화된 터널──── 서버
(TLS 레이어)

PyTorch의 Dropout과 비슷하게 생각할 수 있습니다. 모델 자체(HTTP)는 동일하지만, 그 위에 보안 레이어(TLS)가 씌워집니다. HTTPS를 쓰면 포트가 443을 기본으로 사용합니다.

클라이언트와 서버가 암호화 통신을 시작하기 전에 TLS 핸드셰이크를 통해 서로를 확인하고 암호화 키를 교환합니다. TLS 1.3 기준으로 흐름은 다음과 같습니다.

클라이언트 서버
│ │
│── ClientHello ──────────────────→ │
│ (지원하는 암호화 방식 목록) │
│ │
│ ←──────── ServerHello + 인증서 ── │
│ (선택된 암호화 방식, 공개키) │
│ │
│ [인증서 검증: CA 서명 확인] │
│ │
│── Finished ────────────────────→ │
│ (대칭키 생성 완료) │
│ │
│ ←──────────────── Finished ── │
│ │
│ ══ 암호화된 HTTP 통신 시작 ══ │

TLS 1.3에서는 핸드셰이크가 1-RTT(왕복 1회) 로 완료됩니다. 이전 TLS 1.2는 2-RTT가 필요했습니다.

인증서: “이 서버가 진짜인가” 증명

섹션 제목: “인증서: “이 서버가 진짜인가” 증명”

인증서(Certificate)는 서버의 신원을 보증합니다. 인증기관(CA, Certificate Authority)이 서명합니다.

인증서에 담긴 정보:
- 도메인: api.mymodel.com
- 공개키: (RSA 또는 ECDSA 공개키)
- 발급자: Let's Encrypt Authority X3
- 유효기간: 2026-01-01 ~ 2026-04-01
- CA 서명: (CA의 개인키로 서명)

브라우저는 운영체제에 내장된 신뢰할 수 있는 CA 목록을 가지고 있습니다. 서버 인증서가 이 CA 중 하나로 서명되어 있으면 신뢰합니다.

Let’s Encrypt로 무료 인증서 발급

섹션 제목: “Let’s Encrypt로 무료 인증서 발급”
Terminal window
# certbot 설치 및 nginx용 인증서 발급
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d api.mymodel.com
# 자동 갱신 설정 (인증서 유효기간 90일)
sudo crontab -e
# 0 0 * * * certbot renew --quiet

Let’s Encrypt는 무료 인증서를 제공하는 비영리 CA입니다. nginx와 연동하면 자동으로 인증서를 갱신합니다.

HTTP/1.1에서는 하나의 TCP 연결에서 요청을 순차적으로 처리합니다.

HTTP/1.1:
연결1: [요청A] → [응답A] → [요청B] → [응답B] (순차 처리)
연결2: [요청C] → [응답C]
연결3: [요청D] → [응답D]

브라우저는 이를 해결하려고 도메인당 6개 병렬 연결을 열지만, 각 연결 내에서는 여전히 순차적입니다. 앞선 큰 응답이 뒤의 작은 요청을 막는 현상을 HOL(Head-Of-Line) 블로킹 이라 합니다.

HTTP/2는 하나의 TCP 연결에서 여러 요청/응답을 동시에 처리합니다.

HTTP/2 (하나의 연결):
스트림1: [요청A프레임] ──→ [응답A프레임]
스트림2: [요청B프레임] ──→ [응답B프레임]
스트림3: [요청C프레임] ──→ [응답C프레임]

HTTP/2의 주요 특징입니다.

특징설명
멀티플렉싱하나의 연결에서 여러 스트림 동시 처리
바이너리 프레이밍텍스트 대신 바이너리로 파싱 효율 향상
헤더 압축(HPACK)반복되는 헤더를 압축해 전송
서버 푸시클라이언트 요청 전에 리소스를 먼저 전송 (현재 잘 사용 안 함)

LLM 스트리밍에서 HTTP/2가 유리한 이유

섹션 제목: “LLM 스트리밍에서 HTTP/2가 유리한 이유”

LLM이 토큰을 하나씩 생성해 스트리밍으로 보낼 때, HTTP/1.1에서는 하나의 연결을 응답이 끝날 때까지 점유합니다. HTTP/2에서는 다른 스트림과 연결을 공유하므로 자원 효율이 높습니다.

# FastAPI SSE 스트리밍 예시
from fastapi.responses import StreamingResponse
@app.post("/stream")
async def stream_predict(request: PredictRequest):
async def generate():
async for token in model.stream(request.text):
yield f"data: {token}\n\n"
return StreamingResponse(generate(), media_type="text/event-stream")

nginx가 HTTP/2를 지원하도록 설정하면 클라이언트와 nginx 사이는 HTTP/2로, nginx와 FastAPI 사이는 HTTP/1.1로 통신합니다. (nginx가 종단점 역할)

HTTP/3: QUIC 기반의 차세대 프로토콜

섹션 제목: “HTTP/3: QUIC 기반의 차세대 프로토콜”

HTTP/2는 TCP 레벨의 HOL 블로킹 문제가 남아있습니다. 패킷 하나가 손실되면 TCP가 재전송할 때까지 전체 연결이 대기합니다.

HTTP/3는 TCP 대신 QUIC 프로토콜을 사용합니다.

HTTP/1.1, HTTP/2: [애플리케이션] → HTTP → TCP → IP
HTTP/3: [애플리케이션] → HTTP/3 → QUIC → UDP
비교HTTP/2 (TCP)HTTP/3 (QUIC)
전송 계층TCPUDP (QUIC)
연결 수립TLS 핸드셰이크 별도TLS 1.3 내장 (0/1-RTT)
HOL 블로킹TCP 레벨 존재스트림 독립적
네트워크 변경연결 끊김연결 ID로 유지

모바일 환경처럼 네트워크가 자주 바뀌는 경우(Wi-Fi → LTE) HTTP/3는 연결을 유지하면서 계속 통신할 수 있어 유리합니다.

Terminal window
# nginx에서 HTTP/3 활성화 (nginx 1.25+)
server {
listen 443 quic reuseport;
listen 443 ssl;
add_header Alt-Svc 'h3=":443"; ma=86400';
}

HTTP/3는 아직 보편적이지 않지만 Cloudflare, Google, Meta 등이 이미 프로덕션에서 사용 중입니다.

1. API 키 보호: Authorization 헤더가 평문이면 가로채기 가능
2. 모델 입력/출력 보호: 사용자 데이터가 암호화됨
3. 브라우저 신뢰: HTTPS 없이는 브라우저가 경고 표시
4. HTTP/2 사용: 대부분의 브라우저가 HTTP/2를 HTTPS에서만 허용

실무에서는 Let’s Encrypt + Certbot + nginx 조합이 가장 간편합니다. 이 설정은 02-05 챕터에서 실제 nginx 설정으로 다룹니다.

  • HTTPS는 HTTP에 TLS 암호화를 추가한 것이다. API 키와 사용자 데이터를 보호하려면 반드시 필요하다.
  • TLS 핸드셰이크는 서버 인증서 검증과 암호화 키 교환을 수행한다. TLS 1.3은 1-RTT로 완료된다.
  • Let’s Encrypt + Certbot으로 무료 인증서를 자동 발급·갱신할 수 있다.
  • HTTP/2는 멀티플렉싱으로 HOL 블로킹을 해결한다. LLM 스트리밍처럼 긴 응답과 다른 요청이 공존할 때 유리하다.
  • HTTP/3는 QUIC(UDP 기반)을 사용해 TCP의 한계를 극복한다. 모바일 환경과 고지연 네트워크에서 특히 유리하다.