본문 바로가기

Notice
Recent Posts
Link
Calendar
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Total
Today
관리 메뉴

HTTPS는 어떻게 안전한 걸까? 본문

Etc

HTTPS는 어떻게 안전한 걸까?

BinaryNumber 2026. 5. 17. 13:59
반응형

TLS 인증서 파헤치기

들어가며

브라우저 주소창에 자물쇠 아이콘이 뜨면 "안전하다"고 느끼죠. 그런데 그게 왜 안전한 건지 설명할 수 있나요?

그 핵심에 TLS 인증서가 있습니다. 이 글에서는 TLS가 뭔지, 인증서가 어떻게 신뢰를 만들어내는지를 최대한 쉽게 풀어봅니다.


TLS가 뭔가요? SSL이랑 다른 건가요?

TLS(Transport Layer Security)는 네트워크 통신을 암호화하는 프로토콜입니다. SSL(Secure Sockets Layer)의 후속 버전인데, SSL이라는 이름이 워낙 익숙해져서 지금도 혼용해서 부르는 경우가 많아요.

정리하면:

  • SSL → 오래된 버전, 현재는 보안 취약점으로 사용 안 함
  • TLS 1.2 → 현재도 널리 쓰임
  • TLS 1.3 → 최신 버전, 더 빠르고 안전함

"SSL 인증서 발급받으세요"라고 하면 실제로는 TLS 인증서를 말하는 겁니다.


TLS가 해주는 세 가지

TLS는 크게 세 가지를 보장합니다.

암호화 (Encryption)

주고받는 데이터를 제3자가 볼 수 없도록 암호화합니다. 카페 와이파이에서 누군가 패킷을 가로채도 내용을 읽을 수 없어요.

인증 (Authentication)

지금 연결한 서버가 진짜 그 서버인지 확인합니다. 피싱 사이트가 naver.com인 척 흉내 내도, 인증서가 없으면 브라우저가 경고를 띄웁니다.

무결성 (Integrity)

전송 중에 데이터가 변조되지 않았음을 보장합니다. 중간에서 누군가 내용을 슬쩍 바꿔도 감지할 수 있어요.


인증서란 무엇인가요?

인증서는 쉽게 말해 "이 서버는 믿어도 됩니다"라는 공인된 신분증입니다.

인증서 안에는 이런 정보가 들어 있어요:

  • 도메인 이름 (예: example.com)
  • 공개 키 (public key)
  • 발급자 (인증 기관, CA)
  • 유효 기간
  • 디지털 서명

브라우저는 서버에 접속할 때 이 인증서를 받아서 "이게 진짜인지" 검증합니다.


CA가 뭔데 믿을 수 있는 거예요?

CA(Certificate Authority, 인증 기관)는 인증서를 발급하고 서명하는 기관입니다. DigiCert, Let's Encrypt, Comodo 같은 곳들이에요.

브라우저(크롬, 파이어폭스 등)와 OS(윈도우, 맥 등)에는 신뢰하는 CA 목록이 미리 내장돼 있습니다. 이걸 루트 CA 스토어라고 해요.

흐름을 따라가면:

  1. 서버 운영자가 CA에 인증서 발급 신청
  2. CA가 도메인 소유권 등을 검증
  3. CA가 자신의 개인 키로 인증서에 서명 발급
  4. 브라우저가 인증서를 받아서 CA의 공개 키로 서명 검증
  5. 서명이 유효하면 → 신뢰할 수 있는 서버로 간주

즉, CA를 신뢰하기 때문에 CA가 서명한 인증서도 신뢰하는 구조입니다.


인증서 체인 (Certificate Chain)

인증서는 보통 혼자 존재하지 않고 체인을 이룹니다.

루트 CA (Root CA)
  └── 중간 CA (Intermediate CA)
        └── 서버 인증서 (End-entity Certificate)

루트 CA가 직접 모든 인증서에 서명하지 않고, 중간 CA에 권한을 위임합니다. 루트 CA의 개인 키는 오프라인에 보관할 정도로 중요하게 취급해요.

브라우저가 서버 인증서를 받으면, 체인을 따라 루트 CA까지 거슬러 올라가며 검증합니다. 체인이 끊기거나 루트 CA가 신뢰 목록에 없으면 경고가 뜨는 거예요.


TLS 핸드셰이크 — 연결이 맺어지는 과정

TLS 1.2 — 기본 흐름 (2-RTT)

브라우저와 서버가 처음 연결할 때 왕복 2회가 필요합니다.

클라이언트              서버
    │                    │
    │── ClientHello ────►│  1) TLS 버전, 암호화 방식 제안
    │                    │
    │◄─ ServerHello ─────│  2) 암호화 방식 결정 + 인증서 전달
    │   + 인증서           │
    │                    │
    │   [인증서 검증]       │
    │                    │
    │── 키 교환 ─────────► │  3) 공개 키로 암호화된 프리마스터 시크릿 전달
    │                    │
    │◄─ Finished ────────│  4) 핸드셰이크 완료
    │                    │
    │══ 암호화 통신 시작 ══  │

핵심은 세션 키(대칭 키) 를 안전하게 교환하는 과정입니다. 이 세션 키로 이후 모든 데이터를 암호화해요.


TLS 1.3 — 더 빠르고 단순해진 과정 (1-RTT)

TLS 1.3은 ClientHello에 키 교환 정보(key_share)를 함께 보내서 왕복을 1회로 줄였습니다.

key_share란?
ECDHE 키 교환에서 클라이언트가 미리 생성한 임시 공개 키입니다.
클라이언트는 연결 시작 전에 임시 키 쌍(공개 키 + 개인 키)을 만들어두고, 공개 키만 key_share에 담아 보냅니다.
서버도 자신의 임시 키 쌍을 만들어 응답에 공개 키를 담아 보내면,
양쪽이 상대방의 공개 키와 자신의 개인 키를 조합해 동일한 세션 키를 독립적으로 계산합니다.
세션 키 자체는 네트워크로 전송되지 않으므로 가로챌 수 없습니다.
클라이언트              서버
    │                    │
    │── ClientHello ────►│  1) TLS 버전 + key_share 동시 전송
    │   + key_share      │
    │                    │
    │◄─ ServerHello ─────│  2) {인증서 + Finished} 암호화해서 전달
    │   + {인증서}         │     (이미 세션 키 생성 완료)
    │   + {Finished}     │
    │                    │
    │── {Finished} ── ──►│  3) 확인 완료
    │                    │
    │══ 암호화 통신 시작 ══│

{} 표시는 이미 암호화된 상태로 전송됨을 의미합니다. TLS 1.2보다 훨씬 일찍 암호화가 시작돼요.

0-RTT 재연결 — 이전에 접속한 적 있다면

같은 서버에 재연결할 때는 이전 세션의 키를 재활용해 첫 패킷부터 데이터를 보낼 수 있습니다.

클라이언트              서버
    │                    │
    │── ClientHello ────►│
    │   + 0-RTT 데이터     │  연결과 동시에 요청 전송
    │                    │
    │◄─ ServerHello ─────│
    │   + {응답}          │
    │                    │
    │ ══ 암호화 통신 시작 ══ │

단, 0-RTT는 재전송 공격(Replay Attack) 위험이 있어서 멱등성이 없는 요청(예: 결제)에는 사용하지 않는 게 좋습니다.

멱등성(Idempotency)이란?
같은 요청을 여러 번 보내도 결과가 똑같은 성질을 말합니다.

멱등성 있음: GET /users/1 (몇 번 요청해도 같은 데이터)
             DELETE /users/1 (이미 삭제된 걸 또 삭제해도 결과 동일)
멱등성 없음: POST /orders (요청이 2번 전송되면 주문이 2개 생김)
             POST /payments (중복 결제 발생)

공격자가 캡처한 0-RTT 패킷을 재전송하면 멱등성 없는 요청은 의도치 않게 두 번 실행될 수 있습니다.

TLS 1.2 vs 1.3 비교

항목 TLS 1.2 TLS 1.3
핸드셰이크 왕복 2-RTT 1-RTT
재연결 1-RTT 0-RTT 가능
키 교환 방식 RSA 또는 DH ECDHE 필수 (전방향 비밀성 보장)
암호화 시작 시점 Finished 이후 ServerHello 직후
지원 암호화 방식 다양 (취약한 것 포함) 5가지로 제한, 강한 것만

키 교환 방식이란?

클라이언트와 서버가 세션 키를 안전하게 공유하는 방법입니다. 세션 키 자체를 네트워크로 직접 보내면 가로챌 수 있기 때문에, 수학적 방법으로 양쪽이 같은 키를 독립적으로 계산해냅니다.

방식 설명
RSA 클라이언트가 서버의 공개 키로 암호화해서 세션 키 전송
DH (Diffie-Hellman) 양쪽이 각자 난수를 만들어 수학적으로 같은 값을 도출
ECDHE DH의 타원곡선 버전, 매 연결마다 새 키 쌍 생성 (TLS 1.3 필수)

ECDHE의 핵심은 전방향 비밀성(Forward Secrecy) 입니다. 매 연결마다 임시 키를 새로 만들기 때문에, 나중에 서버의 개인 키가 유출되더라도 과거 통신 내용은 해독할 수 없어요.


인증서 종류 — 뭐가 다를까요?

도메인 기준

종류 설명
단일 도메인 example.com 하나만 커버
와일드카드 *.example.com — 서브도메인 전체 커버
멀티 도메인(SAN) 여러 도메인을 하나의 인증서로 커버

검증 수준 기준

종류 검증 내용 발급 속도
DV (Domain Validation) 도메인 소유권만 확인 수 분 ~ 즉시
OV (Organization Validation) 도메인 + 조직 실체 확인 수 일
EV (Extended Validation) 도메인 + 조직 법적 실체 엄격 확인 수 주

일반 서비스라면 DV로 충분합니다. Let's Encrypt도 DV 인증서를 발급해줘요.


자주 마주치는 인증서 오류들

NET::ERR_CERT_AUTHORITY_INVALID

인증서를 발급한 CA가 브라우저 신뢰 목록에 없을 때. 자체 서명 인증서(self-signed)나 사설 CA 사용 시 발생합니다.

NET::ERR_CERT_DATE_INVALID

인증서 유효 기간이 만료됐을 때. 갱신을 깜빡하면 바로 서비스 장애로 이어집니다.

NET::ERR_CERT_COMMON_NAME_INVALID

인증서의 도메인과 실제 접속한 도메인이 다를 때. www.example.com 인증서로 example.com에 접속하면 뜰 수 있어요.

SSL_ERROR_RX_RECORD_TOO_LONG

HTTP 포트(80)로 HTTPS 요청이 들어왔을 때 종종 발생합니다. 서버 설정 문제예요.


인증서 관련 자주 쓰는 명령어

# 서버 인증서 정보 확인
openssl s_client -connect example.com:443 -showcerts

# 인증서 파일 내용 확인
openssl x509 -in cert.pem -text -noout

# 만료일만 확인
openssl x509 -in cert.pem -noout -enddate

# CSR (인증서 서명 요청) 생성
openssl req -new -newkey rsa:2048 -nodes \
  -keyout server.key \
  -out server.csr

# 개인 키와 인증서로 만료일 확인 (원격)
echo | openssl s_client -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -dates

마치며

TLS 인증서는 단순히 "자물쇠 아이콘"이 아니라, 암호화·인증·무결성을 한 번에 보장하는 핵심 보안 인프라입니다.

구조를 이해하면 인증서 오류가 왜 뜨는지, 어떻게 해결해야 하는지 훨씬 빠르게 파악할 수 있어요. 다음 번에 브라우저 경고가 뜨면 막연히 "위험하다"가 아니라 어디서 체인이 끊겼는지 찾아보세요.

'Etc' 카테고리의 다른 글

DBMS 종류와 순위  (0) 2021.06.24
컴퓨터시스템 개요  (0) 2021.06.14
Comments