개발에 AtoZ까지

HTTPS 자물쇠가 지켜주는 것과 못 지켜주는 것 — TLS가 실제로 하는 일 본문

프론트엔드

HTTPS 자물쇠가 지켜주는 것과 못 지켜주는 것 — TLS가 실제로 하는 일

AtoZ 개발자 2026. 7. 29. 10:18
반응형

😀 개요

안녕하세요 😀

우리는 매일 HTTPS를 씁니다. 주소창에 자물쇠가 보이면 왠지 안심이 되죠. 그런데 이런 질문에 바로 답하기는 은근히 어렵습니다.

  • "SSL이랑 TLS는 뭐가 다른가요?"
  • "자물쇠가 있으면 이 사이트는 안전한 건가요?"
  • "인증서는 대체 뭘 증명하는 거죠?"

미리 결론을 말씀드리면, HTTPS는 HTTP를 TLS라는 보안 계층으로 감싼 것이고, TLS는 전송 구간 암호화·무결성·서버 도메인 확인 이 세 가지를 해 줍니다. 하지만 자물쇠는 "이 도메인과 암호화된 연결" 이라는 뜻이지, "믿을 만한 사이트" 라는 보증은 아닙니다. 피싱 사이트도 버젓이 HTTPS를 씁니다.

이 글은 예전에 다룬 Socket 통신과 HTTP 통신에서 한 걸음 더 들어가, 그 HTTP를 안전하게 감싸는 TLS가 실제로 무슨 일을 하는지 정리합니다.

🎯 오늘 정리하는 것

이 글을 다 읽으면 아래를 스스로 설명할 수 있습니다.

  • SSL과 TLS, HTTPS가 서로 어떤 관계인지 한 문장으로 말할 수 있습니다.
  • TLS 핸드셰이크가 비대칭→대칭 암호로 안전한 연결을 만드는 과정을 그릴 수 있습니다.
  • 인증서가 무엇을 증명하고 무엇을 증명하지 않는지 구분할 수 있습니다.
  • 자물쇠가 지켜주는 것과 못 지켜주는 것을 나눠 판단할 수 있습니다.

암호학 수식이 아니라, 동작의 큰 그림과 오해의 지점을 잡는 것이 목적입니다.

🧭 근거는 어디서 왔나

시작 전에 밝혀 둡니다. 이 글은 제가 TLS 서버를 직접 뜯어본 경험담이 아니라, 표준 규격과 공식 문서에서 확인한 내용을 그림과 함께 정리한 것입니다. 참고한 자료는 다음과 같습니다.

  • RFC 8446(TLS 1.3) · RFC 5246(TLS 1.2) — 프로토콜 규격
  • RFC 5280(X.509) · CA/Browser Forum Baseline Requirements — 인증서와 발급 규칙
  • RFC 6066(SNI) · RFC 9110(https URI) — 부가 동작
  • MDN Web Docs — Transport Layer Security 설명

버전에 따라 세부는 달라질 수 있으니(특히 TLS 1.2와 1.3), 아래는 현재 표준인 TLS 1.3 기준이고 확인일은 2026년 7월 26일입니다.

🔤 TLS와 SSL, HTTPS는 무슨 관계인가

이름부터 정리하면 오해가 절반은 풀립니다.

SSL은 TLS의 옛 이름입니다. 넷스케이프가 만든 초기 버전이 SSL이었고, 표준화되면서 이름이 TLS로 바뀌었습니다. SSL 3.0 이하는 안전하지 않아 오래전에 폐기됐습니다. 그래서 지금 "SSL 인증서", "SSL 적용"이라고 부르는 건 사실상 TLS를 가리키는 관용어입니다. 실제로 동작하는 건 TLS라고 생각하시면 됩니다.

HTTPS는 별도의 프로토콜이 아니라 HTTP를 TLS 위에서 주고받는 것입니다. 평범한 HTTP 요청·응답을 TLS가 암호화된 통로로 감싸는 구조죠.

그럼 TLS는 무엇을 보장할까요? MDN은 TLS가 연결을 세 가지 방식으로 지킨다고 설명합니다.

그림 1. MDN "Transport Layer Security" 문서. TLS는 ① 암호화(Encryption, 전송 중 도청 방지) ② 무결성(Integrity, 몰래 변조 못 함) ③ 인증(Authentication, 상대가 주장하는 그 대상이 맞음)의 세 가지를 제공하며, 웹에서 HTTP에 적용한 것이 HTTPS이자 중간자(MITM) 공격에 대한 방어라고 설명합니다. 

 

여기서 세 번째 "인증"이 뒤에서 볼 오해의 핵심입니다. 웹에서는 보통 서버가 자기 신원(도메인)을 클라이언트에게 증명하고, 클라이언트는 대개 증명하지 않습니다.

🤝 안전한 연결은 어떻게 만들어지나

암호화를 하려면 양쪽이 같은 비밀 열쇠를 나눠 가져야 합니다. 그런데 도청당할 수 있는 네트워크에서 열쇠를 어떻게 안전하게 나눌까요? 이걸 푸는 과정이 TLS 핸드셰이크입니다.

핵심 아이디어는 두 종류의 암호를 역할을 나눠 쓰는 것입니다.

  • 비대칭 암호(공개키/개인키) — 안전하지만 느립니다. 그래서 열쇠를 합의하고 서버를 확인하는 핸드셰이크에만 씁니다.
  • 대칭 암호(하나의 공유 열쇠) — 빠릅니다. 그래서 핸드셰이크 뒤 실제 데이터 전송에 씁니다.

그림 2. TLS 1.3 핸드셰이크. 브라우저와 서버가 각자 임시 공개키(key_share)를 주고받아 같은 대칭 세션키를 계산하고, 서버는 인증서와 서명으로 신원을 증명합니다. 핸드셰이크가 끝나면 이후 데이터는 빠른 대칭키로 오갑니다.

TLS 1.3 기준으로 흐름을 풀면 이렇습니다.

  • 브라우저가 ClientHello에 지원 암호 목록과 임시 공개키(key_share)를 담아 보냅니다.
  • 서버가 ServerHello로 쓸 암호를 정하고 자신의 임시 공개키를 돌려줍니다. 이 시점에 양쪽은 각자 계산으로 같은 대칭 세션키를 얻습니다.
  • 서버가 인증서CertificateVerify 서명을 보내 "이 도메인의 인증서와 그 개인키를 내가 갖고 있다"를 증명하고, Finished로 마무리합니다.
  • 이 모든 게 한 번의 왕복(1-RTT) 안에 끝나고, 이후 HTTP 데이터는 대칭키로 암호화돼 오갑니다.

두 가지만 더 짚겠습니다. 첫째, TLS 1.3은 매번 임시 키로 열쇠를 합의합니다. 그래서 서버의 장기 키가 나중에 유출돼도 과거에 주고받은 통신은 풀리지 않습니다(전방향 비밀성). 예전 TLS 1.2에는 클라이언트가 서버의 RSA 공개키로 비밀을 암호화해 넘기는 방식(static RSA)이 있었는데, 이 경우 전방향 비밀성이 없어 TLS 1.3에서는 제거됐습니다. 둘째, TLS 1.3에서는 인증서까지 암호화돼 오갑니다(TLS 1.2에서는 평문이었습니다).

🔒 그럼 왜 중간에서 못 훔쳐보나

핸드셰이크가 끝나면 데이터는 AEAD라는 대칭 암호로 보호됩니다. AEAD는 한 번의 연산으로 기밀성(내용 숨김)과 무결성(변조 감지)을 동시에 제공합니다. TLS 1.3은 아예 AEAD만 허용합니다.

여기서 자주 나오는 질문. "중간에서 누가 서버인 척하면 되지 않나요?" 이게 바로 중간자(MITM) 공격인데, TLS가 막는 지점이 정확히 여기입니다.

그림 3. RFC 8446(TLS 1.3, 2018). 초록에서 TLS를 "도청·변조·위조를 막도록 설계된 방식으로 클라이언트와 서버가 통신하게 해 주는" 프로토콜로 규정합니다. 

 

포인트는 인증서만으로는 서버를 증명하지 못한다는 것입니다. 인증서는 공개돼 있어 누구나 복사할 수 있으니까요. 진짜 증명은 서버가 핸드셰이크 기록에 개인키로 서명하는 CertificateVerify에서 이뤄집니다. 개인키가 없으면 이 서명을 만들 수 없습니다.

그리고 그 인증서는 브라우저가 이미 신뢰하는 뿌리(트러스트 스토어의 루트 CA)까지 연결(체인)돼야 인정됩니다(RFC 5280의 인증 경로 검증). 그래서 공격자가 아무 인증서나 들이밀어도 신뢰 체인에 연결되지 않으면 브라우저가 거부합니다. 공개 CA가 남의 도메인 인증서를 함부로 발급해 주지도 않습니다 — CA/Browser Forum 규칙상 발급 전에 신청자가 그 도메인을 통제하는지 검증해야 하기 때문입니다.

정리하면, 투명한 TLS 가로채기는 클라이언트가 이미 신뢰하는 CA가 그 기기에 심어져 있을 때만 가능합니다. 회사가 관리 PC에 사내 루트 CA를 설치해 트래픽을 검사하는 경우가 대표적인데, 이건 "이미 신뢰를 심어 둔" 특수 상황입니다.

📜 인증서는 무엇을 "증명"하나

이 부분이 가장 큰 오해를 부릅니다. 기본으로 쓰는 도메인 검증(DV) 인증서가 증명하는 것은 딱 하나, "이 인증서 소유자가 그 도메인을 통제한다" 입니다. 그 사이트를 운영하는 회사가 어디인지, 정직한지는 증명하지 않습니다.

  • 인증서는 공개키를 도메인 이름에 묶어 CA가 서명한 문서입니다(X.509).
  • 브라우저는 리프(서버) 인증서 → 중간 CA → 루트 CA로 이어지는 체인이 신뢰 루트까지 닿는지, 유효기간이 지났는지, 도메인 이름이 맞는지를 검사합니다.
  • 어디에도 연결되지 않은 자체 서명(self-signed) 인증서는 브라우저가 "신뢰할 수 없음" 경고를 띄웁니다. 개인 테스트 서버에서 흔히 보는 그 경고입니다.

그래서 인증서가 유효하다 = 그 사이트가 안전하다가 아닙니다. "지금 연결된 상대가 그 도메인의 인증서를 가진 서버가 맞다"까지만 보장합니다.

🔓 그래서 자물쇠가 못 지켜주는 것

이제 오해를 정면으로 정리하겠습니다.

그림 4. 자물쇠는 전송 구간 암호화·무결성·서버 도메인 신원을 지켜 줍니다. 반대로 그 사이트가 안전·정직한지, 서버 안에서 데이터가 안전한지, 어떤 도메인을 방문하는지까지는 지켜 주지 않습니다.

  • "안전한 사이트"라는 보증이 아닙니다. 피싱·악성 사이트도 유효한 HTTPS를 씁니다. 자물쇠는 "이 도메인과의 연결이 암호화됐다"는 뜻이지 "이 사이트를 믿어도 된다"가 아닙니다.
  • 서버에 도착한 뒤의 안전은 별개입니다. TLS는 "가는 길(전송 구간)"만 지킵니다. 서버가 데이터를 어떻게 저장·처리하는지는 TLS의 몫이 아닙니다.
  • 어떤 사이트에 접속하는지는 가려지지 않습니다. 접속할 도메인 이름은 핸드셰이크 초반 ClientHelloSNI에 담겨 보통 평문으로 나갑니다. 그래서 네트워크 관찰자는 내용은 못 봐도 "어느 도메인에 갔는지"는 볼 수 있습니다. 이 부분을 가리려는 것이 ECH(Encrypted Client Hello)입니다.

한 가지 더. HTTPS를 강제하고 사용자가 인증서 경고를 무시하고 들어가지 못하게 하려면 HSTS(Strict-Transport-Security 헤더)를 함께 씁니다. 중간에서 HTTPS를 HTTP로 깎아내리는 공격을 막는 장치입니다.

✅ 개발자가 챙길 체크리스트

서비스에 HTTPS를 적용·점검할 때 이 정도를 짚으면 됩니다. 필요하면 복사해서 쓰세요.

[적용]
- [ ] 모든 페이지·리소스를 HTTPS로 제공하나? (혼합 콘텐츠 없음)
- [ ] HTTP 접속을 HTTPS로 리다이렉트하나?
- [ ] HSTS(Strict-Transport-Security) 헤더를 넣었나?

[인증서]
- [ ] 인증서 만료 전에 자동 갱신되나? (만료 = 접속 차단)
- [ ] 인증서의 도메인(SAN)이 실제 서비스 도메인과 맞나?
- [ ] 중간 CA 인증서까지 체인이 완전한가? (일부 클라이언트에서 체인 끊김 주의)

[버전·설정]
- [ ] TLS 1.2/1.3만 허용하고 옛 SSL/TLS는 껐나?

[오해 점검]
- [ ] "자물쇠 = 안전한 사이트"로 설명하고 있지 않나? (도메인 연결 암호화일 뿐)
- [ ] 사용자 입력·서버 저장 보안을 "HTTPS 썼으니 됐다"로 넘기지 않았나?

🫡 마무리

정리하면, HTTPS는 HTTP를 TLS로 감싼 것이고, TLS는 핸드셰이크에서 비대칭 암호로 열쇠를 합의하고 서버를 확인한 뒤 대칭 암호로 데이터를 주고받습니다. 그리고 자물쇠가 지켜주는 건 전송 구간의 암호화·무결성과 서버 도메인 신원까지입니다.

가장 기억할 한 가지는 이것입니다. 자물쇠는 "안전한 사이트"라는 뜻이 아니라 "이 도메인과 암호화된 연결"이라는 뜻입니다. 인증서(기본 DV)는 도메인 통제를 증명할 뿐, 그 사이트의 정직함까지 보장하지 않습니다.

더 깊이 들어가고 싶다면, 이 위에서 오가는 통신 자체는 Socket 통신과 HTTP 통신 비교를, 로그인 상태와 인증은 세션 vs JWT 인증소셜 로그인과 OAuth 2.0을, 다른 출처로 요청이 오갈 때 나는 CORS 에러를 함께 보시면 좋습니다.

읽어 주셔서 감사합니다 🙇

참고 자료

반응형
Comments