사전 HTTPS
프로토콜

HTTPS

gabury1고친 사람 github-actions[bot]

HTTPS 는 웹 요청과 응답을 남이 읽거나 고치지 못하게 잠가서 주고받는 방식입니다. 주고받는 내용은 보통의 웹 요청과 같습니다. 다른 점은 대화를 시작하기 전에 상대가 진짜인지 확인하고 암호화된 통로부터 연다는 것입니다.

쉽고 빠른 이해

HTTPS 는 웹 요청을 잠긴 통로 안으로 보내는 방식입니다. 주소창의 https:// 가 그 표시입니다. 로그인 비밀번호와 쿠키가 이 통로로 오갑니다.

이게 없으면 카페 와이파이나 중간 공유기에서 누구나 요청 내용을 읽을 수 있습니다. 응답을 몰래 바꿔 끼워도 받는 쪽은 알아채지 못합니다.

어떻게 도는가:

  1. 브라우저가 서버에 연결하고 서버의 신분증인 인증서를 받습니다
  2. 믿을 만한 기관이 서명한 인증서인지, 주소와 이름이 맞는지 확인합니다
  3. 둘만 아는 열쇠를 맞춘 뒤 그 열쇠로 요청과 응답을 잠가 주고받습니다

대가도 있습니다. 첫 연결에 인사 과정이 더 붙어 응답이 조금 늦어집니다. 인증서를 발급받고 만료 전에 갈아 끼우는 일도 생깁니다.

그래도 공개 인터넷을 지나는 웹 통신은 사실상 전부 HTTPS 로 합니다. 앞단 서버에서 암호를 푼 뒤 사설망 안쪽 구간만 평문 HTTP 로 두기도 합니다.

상세

HTTPS(HyperText Transfer Protocol Secure)는 HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜) 메시지를 TLS(Transport Layer Security, 전송 계층 보안)로 감싸서 주고받는 방식입니다. 새 프로토콜을 따로 만든 것이 아니라 두 프로토콜을 겹쳐 쓴 것입니다. 이 절은 무엇을 지켜 주는지, 연결이 어떤 순서로 열리는지, 무엇을 대가로 치르는지를 차례로 봅니다.

봉투에 넣은 편지로 생각하면 쉽습니다. 엽서는 배달하는 사람 누구나 읽을 수 있습니다. 봉투에 넣고 봉인하면 안의 편지는 받는 사람만 엽니다. 다만 겉면의 주소는 여전히 보입니다.

HTTP 와 TLS 를 겹친 구조

HTTP 는 요청과 응답의 모양을 정하는 프로토콜입니다. HTTP 만으로 보내면 메시지가 평문 그대로 선을 탑니다. 평문은 암호화하지 않아 누구나 읽을 수 있는 데이터를 말합니다.

HTTPS 에서는 HTTP 와 TCP(Transmission Control Protocol, 전송 제어 프로토콜) 사이에 TLS 가 끼어듭니다. HTTP 는 평소처럼 요청을 만듭니다. TLS 가 그 바이트를 암호화해 TCP 에 넘깁니다. 받는 쪽은 거꾸로 풀어서 HTTP 에 건넵니다. 그래서 애플리케이션 코드는 대개 HTTP 를 쓸 때와 똑같이 짭니다.

TCP 아래에는 IP(Internet Protocol, 인터넷 프로토콜)가 있습니다. IP 는 데이터를 패킷으로 목적지까지 나르는 층입니다. 아래 그림은 이 네 층이 쌓인 모습입니다.

flowchart TD
    subgraph S["HTTPS 한 연결"]
        H["HTTP · 요청과 응답"]
        T["TLS · 암호화와 인증"]
        C["TCP · 바이트를 순서대로 나름"]
        I["IP · 패킷을 목적지로 나름"]
    end
    H --> T --> C --> I

주소도 이 구분을 드러냅니다. URL(Uniform Resource Locator, 자원 위치 주소)이 https:// 로 시작하면 HTTPS 로, http:// 로 시작하면 평문 HTTP 로 연결합니다. 포트를 적지 않으면 HTTPS 는 443 번, HTTP 는 80 번 포트로 갑니다.

http://example.com/login    // 80 · 평문
https://example.com/login   // 443 · TLS

지켜 주는 세 가지

HTTPS 가 막는 위협은 크게 셋입니다. 셋이 서로 다른 문제라서 따로 짚어야 합니다.

성질 막는 것 빠지면 생기는 일
기밀성 엿보기 비밀번호와 쿠키가 그대로 읽힌다
무결성 몰래 고치기 중간에서 응답에 광고나 악성 스크립트를 끼운다
인증 남인 척하기 가짜 서버가 진짜인 척 요청을 받는다

셋 가운데 인증이 가장 놓치기 쉽습니다. 암호화만 하고 상대를 확인하지 않으면 공격자와 암호화된 대화를 나누게 됩니다. 중간에 끼어든 공격자가 양쪽에 각각 통로를 열고 내용을 옮겨 주면 됩니다. 이런 공격이 중간자 공격입니다. 인증서 확인이 이 공격을 막습니다.

인증서로 서버를 확인하는 과정

인증서를 보기 전에 열쇠 한 쌍부터 알아야 합니다. 공개 키는 누구에게 알려도 되는 열쇠입니다. 짝이 되는 개인 키는 서버만 갖습니다. 서버는 개인 키로만 할 수 있는 계산을 해 보여서 자기가 그 공개 키의 진짜 주인임을 증명합니다.

그런데 공개 키만 받아서는 그 키가 정말 그 도메인의 것인지 모릅니다. 이 빈틈을 인증서가 메웁니다. 인증서는 「이 공개 키의 주인은 이 도메인이다」라고 적고 믿을 만한 기관이 서명한 문서입니다. 서명하는 기관이 인증 기관(Certificate Authority, CA)입니다.

서명은 보통 여러 단계로 이어집니다. 서버 인증서에는 중간 인증서가 서명하고, 그 중간 인증서에는 다시 CA 의 최상위 인증서가 서명합니다. 클라이언트는 이 사슬을 거슬러 올라가 끝이 자기가 믿는 CA 인지 봅니다.

믿을 CA 목록은 운영체제나 브라우저가 미리 갖고 있습니다. 이 목록이 신뢰 저장소입니다.

브라우저나 HTTP 클라이언트는 서버가 보낸 인증서에서 세 가지를 봅니다. 서명 사슬이 신뢰 저장소의 CA 까지 닿는지, 인증서에 적힌 이름이 접속한 도메인과 맞는지, 유효 기간 안인지입니다. 셋 중 하나라도 어긋나면 연결을 끊거나 경고를 띄웁니다.

curl -k 처럼 이 확인을 끄는 옵션을 쓰면 암호화는 되어도 인증은 사라집니다. 앞에서 본 중간자 공격을 그대로 열어 주는 셈입니다.

연결이 열리는 순서

HTTPS 요청 하나가 처음 나갈 때는 세 단계를 거칩니다. 가운데 단계인 핸드셰이크는 본 대화 전에 양쪽이 조건을 맞추는 인사 과정입니다.

  1. 먼저 TCP 연결을 맺습니다
  2. 다음에 TLS 핸드셰이크로 암호화 통로를 엽니다
  3. 그 뒤에 HTTP 요청을 보냅니다
sequenceDiagram
    participant 클라이언트
    participant 서버
    클라이언트->>서버: TCP 연결 요청
    서버-->>클라이언트: TCP 연결 수락
    클라이언트->>서버: TLS 시작 · 지원하는 암호 방식
    서버-->>클라이언트: 고른 방식 · 인증서
    Note over 클라이언트: 인증서를 확인하고 열쇠를 맞춘다
    클라이언트->>서버: 암호화된 HTTP 요청
    서버-->>클라이언트: 암호화된 HTTP 응답

핸드셰이크 안에서 쓰는 암호 방식은 두 가지입니다. 대칭 키 암호는 같은 열쇠 하나로 잠그고 여는 방식입니다. 빠르지만 두 사람이 같은 열쇠를 먼저 나눠 가져야 합니다.

공개 키 암호는 공개 키와 개인 키 한 쌍을 쓰는 방식입니다. 한쪽 열쇠로 잠근 것은 짝이 되는 다른 쪽으로만 풀립니다. 남이 보는 선 위에서도 둘만 아는 값을 만들 수 있지만 계산이 무겁습니다.

그래서 TLS 는 둘을 나눠 씁니다. 핸드셰이크에서는 공개 키 암호로 둘만 아는 열쇠를 맞춥니다. 그 뒤 본 데이터는 그 열쇠로 대칭 키 암호를 써서 잠급니다.

SNI(Server Name Indication, 서버 이름 표시)는 클라이언트가 TLS 를 시작할 때 접속하려는 도메인 이름을 함께 보내는 것입니다. 서버 하나가 여러 도메인을 맡을 때 어느 인증서를 내줄지 고르는 데 씁니다.

암호화되는 것과 드러나는 것

HTTPS 가 모든 것을 가리지는 않습니다. 잠기는 것은 HTTP 메시지 전체입니다. 경로, 쿼리 문자열, 헤더, 쿠키, 본문이 모두 여기 들어갑니다.

드러나는 것도 있습니다. 양쪽의 IP 주소(Internet Protocol address, 인터넷 프로토콜 주소)와 포트는 패킷을 나르려면 보여야 합니다. 접속하는 도메인 이름은 SNI 와 DNS(Domain Name System, 도메인 이름 체계) 조회에서 흔히 보입니다. 주고받는 데이터의 크기와 시간 간격도 보입니다.

https://example.com/users?token=abc 로 요청하면 중간 관찰자는 example.com 에 접속했다는 것까지 압니다. 경로와 token 값은 모릅니다. 다만 URL 은 서버 접근 로그나 브라우저 기록에 남으므로 비밀 값을 쿼리 문자열에 싣지 않는 편이 안전합니다.

치르는 비용

첫 연결에는 TLS 핸드셰이크만큼 네트워크 왕복이 한두 번 더 붙습니다. 서버가 멀수록 왕복 한 번이 길어서 이 지연이 크게 느껴집니다.

이 비용은 연결을 다시 쓰면 줄어듭니다. 한 번 연 연결로 요청을 여러 개 보내면 핸드셰이크는 처음 한 번뿐입니다. 끊겼다가 다시 붙을 때 앞서 맞춘 정보를 재활용하는 세션 재개도 있습니다.

암호화와 복호화에 드는 계산은 요즘 서버에서 대개 작은 편입니다. 운영에서 더 자주 부딪히는 비용은 인증서 관리입니다. 인증서는 만료일이 있어서 제때 갱신하지 않으면 그날부터 모든 클라이언트가 접속에 실패합니다.

TLS 를 끝내는 지점

서비스에서는 애플리케이션 서버가 TLS 를 직접 풀지 않는 경우가 많습니다. 앞단의 로드 밸런서나 리버스 프록시가 HTTPS 를 받아 풉니다. 뒤쪽 서버에는 평문 HTTP 로 넘깁니다. 이렇게 앞단에서 암호를 푸는 구성이 TLS 종료입니다.

flowchart TD
    A["클라이언트"] -->|"HTTPS"| B["로드 밸런서 · TLS 를 푼다"]
    B -->|"HTTP"| C["애플리케이션 서버 1"]
    B -->|"HTTP"| D["애플리케이션 서버 2"]

이렇게 하면 인증서를 앞단 한 곳에서만 관리합니다. 애플리케이션 서버마다 인증서를 깔고 갱신할 필요가 없습니다.

대신 뒤쪽 서버는 원래 요청이 HTTPS 였는지 모릅니다. 그래서 앞단이 X-Forwarded-Proto 같은 헤더에 원래 방식을 적어 넘깁니다. 애플리케이션은 그 값을 보고 리다이렉트 주소나 쿠키 설정을 정합니다.

이 헤더를 안 보면 사고가 납니다. 애플리케이션은 흔히 평문 HTTP 로 들어온 요청을 HTTPS 주소로 돌려보내는 리다이렉트를 걸어 둡니다. 그러면 다음 순서가 끝없이 되풀이됩니다.

  1. 앞단이 HTTPS 요청을 풀어 HTTP 로 넘깁니다
  2. 애플리케이션이 평문 요청으로 여겨 HTTPS 주소로 리다이렉트합니다
  3. 브라우저가 HTTPS 로 다시 요청합니다
  4. 이 요청이 다시 1번부터 같은 길을 밟습니다

HTTP 에서 HTTPS 로 옮겨 가게 하는 장치

사용자가 주소창에 http:// 로 들어오면 서버는 보통 HTTPS 주소로 리다이렉트합니다. 그런데 그 첫 요청은 평문이라 중간에서 가로챌 수 있습니다.

HSTS(HTTP Strict Transport Security)는 이 틈을 줄입니다. 서버가 Strict-Transport-Security 응답 헤더를 보내면 브라우저는 정해진 기간 동안 그 도메인에 HTTPS 로만 접속합니다. 사용자가 http:// 를 쳐도 브라우저가 요청을 내보내기 전에 바꿔 버립니다.

HTTPS 페이지 안에서 HTTP 로 불러오는 스크립트나 이미지가 혼합 콘텐츠입니다. 평문으로 받은 스크립트는 중간에서 바뀔 수 있어서 페이지 전체의 보호가 깨집니다. 브라우저는 이런 요청을 막거나 경고합니다.

SSL 이라는 옛 이름

TLS 의 앞선 이름은 SSL(Secure Sockets Layer, 보안 소켓 계층)입니다. 옛 SSL 판들은 약점이 드러나 더는 쓰지 않습니다. 그래도 실무에서는 「SSL 인증서」·「SSL 설정」이라는 말이 남아 있습니다. 이 말은 대개 TLS 를 가리킵니다.

관련 항목

HTTPS 를 이루는 프로토콜

HTTP · TLS · TCP · IP · QUIC · HTTP/2 · HTTP/3 · SSL

HTTPS 가 지키는 성질

기밀성 · 무결성 · 인증 · 암호화 · 평문

HTTPS 연결이 거치는 처리 단계

TCP 핸드셰이크 · TLS 핸드셰이크 · 핸드셰이크 · SNI · ALPN · 세션 재개 · 0-RTT

HTTPS 를 받치는 인증서와 암호

인증서 · X.509 · 인증 기관 · 루트 인증서 · 인증서 체인 · 신뢰 저장소 · 공개 키 · 공개 키 암호 · 대칭 키 암호 · 공개 키 기반구조 · Let's Encrypt

HTTPS 를 강제하거나 깨뜨리는 브라우저 규칙

HSTS · 혼합 콘텐츠 · 리다이렉트 · 보안 쿠키 · 보안 컨텍스트

HTTPS 를 노리는 공격

중간자 공격 · 다운그레이드 공격 · SSL 스트리핑 · 인증서 위조 · 도청

HTTPS 연결을 받아 넘기는 중간 장비

로드 밸런서 · 리버스 프록시 · TLS 종료 · CDN · 프록시 · nginx · 게이트웨이

HTTPS 로 접근하는 대상

원격 저장소 · REST · API · 오리진 서버 · 웹 서버

HTTPS 사용으로 늘어나는 지표

지연 · 왕복 시간 · 첫 바이트까지의 시간 · 응답 시간

HTTPS 주소를 이루는 구성 요소

URL · URI · 포트 번호 · 도메인 이름 · DNS · 쿼리 문자열 · 헤더 · 쿠키

다른 이름: HyperText Transfer Protocol Secure · HTTP over TLS · 보안 HTTP