IT Series · Chapter 2

mTLS(Mutual Transport Layer Security) 개념 정리

작성자: Choi.eth

13 min read

Intro: TLS(Transport Layer Security)란?

  • TLS(Transport Layer Security): 클라이언트와 서버가 네트워크에서 데이터를 안전하게 주고받을 수 있도록 보호하는 보안 프로토콜
  • HTTPS: HTTP에 TLS를 적용한 대표적인 프로토콜
sequenceDiagram
    autonumber
    participant C as Client
    participant S as Server

    C->>S: 1. TLS 연결 요청
    S-->>C: 2. 서버 인증서 전달
    Note over C: 3. 인증서 유효성 및 신뢰 여부 검증
    C->>S: 4. TLS 핸드셰이크 수행<br/>공유 비밀 생성 및 세션 키 도출
    C->>S: 5. 암호화된 HTTP 요청
    S-->>C: 6. 암호화된 HTTP 응답

TLS는 크게 두 가지 역할을 수행합니다.

  • 암호화(Encryption): 통신 내용을 암호화하여 제3자가 데이터를 읽지 못하도록 보호
  • 인증(Authentication): 인증서를 통해 통신 상대가 신뢰할 수 있는 서버인지 검증

일반적인 TLS 통신에서는 서버만 인증서를 제시하고, 클라이언트가 서버의 신원을 검증합니다.

mTLS(Mutual Transport Layer Security)

mTLS(Mutual TLS)는 서버와 클라이언트가 서로의 신원을 인증하는 TLS 방식입니다. 일반적인 TLS에서는 클라이언트가 서버의 신원만 확인하지만, mTLS에서는 서버도 클라이언트의 신원을 확인합니다.

이처럼 양쪽이 서로의 신원을 검증하는 과정을 상호 인증(Mutual Authentication)이라고 합니다.

mTLS에서 사용하는 인증서와 키

Client
├── ca.crt
├── client.crt
└── client.key

Server
├── ca.crt
├── server.crt
└── server.key

mTLS에서는 일반적으로 클라이언트와 서버가 각각 자신의 인증서와 개인키, 그리고 신뢰할 수 있는 CA 인증서를 가지고 있습니다. 각 파일의 역할은 다음과 같습니다.

  • ca.crt: CA 공개키를 포함하며 상대방 인증서의 신뢰성을 검증
  • server.crt: 서버의 신원 정보와 공개키, CA 전자서명 포함
  • server.key: 서버가 개인키 소유를 증명하기 위해 사용
  • client.crt: 클라이언트의 신원 정보와 공개키, CA 전자서명 포함
  • client.key: 클라이언트가 개인키 소유를 증명하기 위해 사용
  • ca.key: CA가 새로운 인증서를 발급하고 서명할 때 사용

여기서 ca.key는 실제 mTLS 통신에 필요하지 않습니다. 인증서를 발급하고 서명할 때 사용하는 CA의 개인키이므로, 안전한 장소에 별도로 보관해야 합니다.

mTLS의 핵심 원리

mTLS의 상호 인증은 클라이언트와 서버가 서로에 대해 다음 두 가지 검증을 수행하는 방식으로 이루어집니다.

인증서의 신뢰성 검증

먼저 상대방이 제출한 인증서가 신뢰할 수 있는 CA(Certificate Authority)에 의해 발급되었는지 확인합니다.

여기서 CA는 인증서에 포함되는 공개키와 신원 정보를 인증하고 전자서명하는 주체 또는 기관입니다. 클라이언트와 서버는 자신이 신뢰하는 CA의 인증서를 이용해 상대방이 제출한 인증서의 신뢰성을 검증합니다.

server.crt
├── 인증서 정보 (TBS Certificate)
│   ├── 서버 공개키
│   ├── 도메인
│   ├── 유효기간
│   └── 발급자 정보
│
└── CA의 전자서명

클라이언트는 서버가 전달한 server.crt의 인증서 정보와 CA 전자서명을 자신이 보유한 ca.crt의 공개키를 이용해 검증합니다. 이를 통해 서버 인증서가 신뢰할 수 있는 CA에 의해 서명되었는지 확인할 수 있습니다.

반대로 서버가 클라이언트를 인증할 때도 client.crt와 신뢰하는 CA 인증서를 이용해 동일한 검증 과정을 수행합니다.

개인키 소유 증명(Proof of Possession)

인증서가 유효하다고 해서 통신 상대방이 해당 인증서의 실제 소유자라는 보장은 없습니다. 인증서는 공개할 수 있는 정보이므로, 공격자가 다른 서버의 인증서를 복사해 사용할 수도 있기 때문입니다.

이를 방지하기 위해 TLS는 개인키 소유 증명(Proof of Possession)을 수행합니다.

sequenceDiagram
    autonumber
    participant S as Server
    participant C as Client

    Note over S: server.key (개인키)로<br/>핸드셰이크 데이터에 전자서명

    S->>C: CertificateVerify (전자서명 값)

    Note over C: server.crt에 포함된<br/>서버 공개키로 서명 검증

    Note over C: 검증 성공 시<br/>서버의 개인키 소유 확인
  1. 서버가 자신의 개인키(server.key)로 핸드셰이크 데이터에 전자서명
  2. 생성한 서명값을 CertificateVerify 메시지로 클라이언트에 전달
  3. 클라이언트가 서버 인증서(server.crt)에 포함된 공개키로 서명을 검증
  4. 검증에 성공하면 서버가 해당 개인키를 실제로 소유하고 있음을 확인

서버가 앞서 전달한 server.crt에는 서버의 공개키가 포함되어 있습니다. 따라서 클라이언트는 CertificateVerify 메시지를 받기 전부터 서버의 공개키를 알고 있으며, 이를 이용해 전달받은 전자서명을 검증할 수 있습니다.

즉, 공격자가 서버의 인증서를 복사해 인증에 사용하더라도 인증서에 대응하는 개인키가 없다면 올바른 전자서명을 생성할 수 없습니다. 결국 개인키 소유 증명 과정에서 검증에 실패하므로 인증을 완료할 수 없습니다.

mTLS의 핵심 원리

sequenceDiagram
    autonumber
    participant C as Client
    participant S as Server

    Note over C,S: 1. TLS 연결 및 키 교환
    C->>S: ClientHello + 임시 공개키
    S-->>C: ServerHello + 임시 공개키
    Note over C,S: 공유 비밀 계산 및 Handshake 키 도출

    Note over C,S: 2. 서버 인증
    S-->>C: CertificateRequest + server.crt
    S-->>C: CertificateVerify + Finished
    Note left of C: ca.crt로 인증서 서명 검증
    Note left of C: server.crt로 서버의 서명 검증

    Note over C,S: 3. 클라이언트 인증
    C->>S: client.crt
    C->>S: CertificateVerify + Finished
    Note right of S: ca.crt로 인증서 서명 검증
    Note right of S: client.crt로 클라이언트의 서명 검증

    Note over C,S: 4. 상호 인증 완료
    Note over C,S: Application Traffic Key 도출 및 사용

    Note over C,S: 5. 암호화 통신
    C->>S: 암호화된 HTTP / RPC 요청
    S-->>C: 암호화된 HTTP / RPC 응답

TLS 1.3을 기준으로 mTLS의 전체 동작 과정을 크게 다섯 단계로 구분할 수 있습니다.

1단계 — TLS 연결 및 키 교환

클라이언트와 서버는 일반적으로 ECDHE(Elliptic Curve Diffie-Hellman Ephemeral)를 사용해 임시 공개키를 교환합니다.

이후 각자 자신의 임시 개인키와 상대방의 임시 공개키를 이용해 동일한 공유 비밀을 계산하고, 이를 바탕으로 핸드셰이크 암호화 키를 도출합니다.

ECDHE(Elliptic Curve Diffie-Hellman Ephemeral)

sequenceDiagram
    participant C as Client
    participant S as Server

    Note over C: 임시 개인키 A 생성
    Note over C: 임시 공개키 A 생성
    Note over S: 임시 개인키 B 생성
    Note over S: 임시 공개키 B 생성

    C->>S: ClientHello (공개키 A)
    S-->>C: ServerHello (공개키 B)

    Note over C: 개인키 A + 공개키 B
    Note over C: 공유 비밀 계산

    Note over S: 개인키 B + 공개키 A
    Note over S: 공유 비밀 계산

    Note over C,S: 양쪽의 공유 비밀이 동일함

ECDHE는 키 교환 방식 중 하나입니다. ECDHE에서 임시 개인키와 공개키를 사용하는 이유는 클라이언트와 서버가 개인키를 서로에게 알려주지 않고도 동일한 비밀값을 계산할 수 있기 때문입니다.

이렇게 계산한 공유 비밀을 바탕으로 암호화 키를 도출하면, 서로를 인증하는 핸드셰이크 과정에서 주고받는 메시지를 암호화하고 복호화할 수 있습니다.

공유 비밀(Shared Secret)

클라이언트와 서버의 임시 개인키를 각각 a,ba, b라고 하고, 타원곡선의 기준점을 GG라고 가정하겠습니다.

  • 클라이언트 공개키:(A=aGA=aG
  • 서버 공개키:(B=bGB=bG

서로 공개키를 교환한 뒤, 각자 자신의 개인키와 상대방의 공개키를 이용해 공유 비밀을 계산합니다.

위와 같이 클라이언트는 aBaB, 서버는 bAbA를 계산하며, 양쪽 모두 동일한 abGabG라는 공유 비밀을 얻을 수 있습니다.

여기서 aGaG, bGbG는 일반적인 숫자 곱셈이 아니라 타원곡선의 점에 대한 스칼라 곱셈입니다. 타원곡선 암호학의 수학적 성질로 인해 공격자가 네트워크에서 공개키 AA와 BB를 가로채더라도 개인키 aa 또는 bb를 계산하는 것은 현실적으로 매우 어렵습니다.

대칭키 암호화를 활용한 메시지 암복호화

계산한 공유 비밀을 HTTP 데이터 암호화에 직접 사용하는 것은 아닙니다. TLS 1.3에서는 공유 비밀을 HKDF라는 키 도출 함수에 입력하여 실제 통신에 사용할 암호화 키를 생성합니다.

클라이언트와 서버는 동일한 공유 비밀을 계산하므로, 이를 바탕으로 서로 대응하는 암호화 키를 도출할 수 있습니다. 이후 송신 방향별로 도출된 대칭키를 사용해 메시지를 암호화하고, 수신 측에서는 해당 키로 메시지를 복호화합니다.

2단계 — 서버 인증

서버 인증 단계에서는 클라이언트가 서버 인증서의 신뢰성과 서버의 개인키 소유 여부를 검증합니다.

  1. 서버가 Certificate 메시지로 서버 인증서(server.crt)를 전달하고, CertificateVerify 메시지로 자신의 개인키(server.key)를 사용해 생성한 핸드셰이크 전자서명을 전달
  2. 클라이언트가 ca.crt를 이용해 server.crt의 CA 전자서명을 검증하고, 이후 CertificateVerify 메시지로 받은 서버의 전자서명을 server.crt에 포함된 공개키로 검증

3단계 — 클라이언트 인증

클라이언트 인증 단계에서는 반대로 서버가 클라이언트 인증서의 신뢰성과 클라이언트의 개인키 소유 여부를 검증합니다.

  1. 서버의 CertificateRequest에 따라 클라이언트가 Certificate 메시지로 자신의 인증서(client.crt)를 전달하고, CertificateVerify 메시지로 개인키(client.key)를 사용해 생성한 핸드셰이크 전자서명을 전달
  2. 서버가 ca.crt를 이용해 client.crt의 CA 전자서명을 검증하고, 이후 CertificateVerify 메시지로 받은 클라이언트의 전자서명을 client.crt에 포함된 공개키로 검증

4단계 — 상호 인증 완료

클라이언트와 서버 양쪽에서 인증서의 신뢰성 검증과 개인키 소유 증명, 핸드셰이크 무결성 검증이 모두 성공하면 상호 인증이 완료됩니다.

5단계 — 암호화 통신

상호 인증이 완료되면 클라이언트와 서버는 키 교환 결과를 바탕으로 도출한 애플리케이션 트래픽 키를 사용해 데이터를 암호화하고 무결성을 보호합니다.

이후 HTTP 또는 RPC 요청과 응답을 암호화된 상태로 주고받을 수 있습니다.

마무리: 인증과 인가

mTLS의 가장 큰 장점은 네트워크 연결 단계에서 통신 주체를 인증할 수 있다는 점입니다. 서버는 클라이언트에 인증서를 요구할 수 있으므로, 애플리케이션 요청을 처리하기 전에 클라이언트의 신원을 확인할 수 있습니다.

다만 여기서 인증(Authentication)과 인가(Authorization)는 구분해야 합니다.

  • 인증(Authentication): 통신 상대가 누구인지 확인하는 과정
  • 인가(Authorization): 인증된 상대에게 어떤 작업을 허용할지 결정하는 과정

예를 들어 클라이언트 인증서가 유효하더라도 해당 클라이언트가 모든 RPC 메서드를 호출할 수 있어야 하는 것은 아닙니다. 이러한 권한은 별도의 인가 정책을 통해 제한할 수 있습니다.

또한 mTLS가 개인키 탈취나 애플리케이션 자체의 취약점까지 해결하는 것은 아닙니다. 따라서 인증서 만료와 갱신, 개인키 보관, 인증서 폐기 및 접근 권한 관리도 함께 고려해야 합니다.