Skip to content

Commit

Permalink
docs: understanding-tls
Browse files Browse the repository at this point in the history
  • Loading branch information
siyul-park committed Sep 18, 2024
1 parent eae2b3a commit 3c290f3
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 1 deletion.
2 changes: 1 addition & 1 deletion _posts/2024-09-08-restful-api-design-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,4 +301,4 @@ Accept-Version: v1.1.6

- [Architectural Styles and the Design of Network-based Software Architectures](https://ics.uci.edu/~fielding/pubs/dissertation/top.htm)
- [논문을 통한 REST에 대한 고찰](https://shoark7.github.io/programming/knowledge/what-is-rest)
- [실용적인 RESTful API 설계에 대해](https://velog.io/@wo_ogie/restful-api-design)
- [실용적인 RESTful API 설계에 대해](https://velog.io/@wo_ogie/restful-api-design)
171 changes: 171 additions & 0 deletions _posts/2024-09-18-understanding-tls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
---
title: "이해하기 쉬운 TLS"
date: 2024-09-18 12:00:00 +0900
categories: "network"
tags: ["network", "http"]
---

초기 웹 통신에서는 제3자가 통신 내용을 엿볼 수 있는 보안 문제가 존재했습니다. 이를 해결하기 위해 1990년대 중반, 넷스케이프(Netscape)는 **SSL**(Secure Sockets Layer) 프로토콜을 개발했습니다. SSL은 클라이언트와 서버 간의 데이터를 암호화하여 외부의 엿보기를 방지하며, **데이터 암호화**, **무결성 검증**, **양측의 신원 인증**을 통해 보안을 강화했습니다. 이로 인해 인터넷 뱅킹과 전자상거래에서 안전한 데이터 전송이 가능해졌습니다.

하지만 시간이 지남에 따라 **SSL**의 보안 취약점이 드러났습니다. 이를 해결하기 위해 1999년에 **Tim Dierks****Christopher Allen****SSL 3.0**의 후속으로 **TLS**(Transport Layer Security) 1.0을 개발했습니다. **TLS**는 SSL의 후계자로서 더 강력한 보안 기능을 제공하며, SSL의 취약점을 보완하도록 설계되었습니다. 오늘날 **TLS**는 SSL과 호환되며 대부분의 현대 시스템에서 널리 사용되고 있습니다.

**TLS**는 두 가지 주요 단계로 구성됩니다. 첫 번째는 **핸드셰이크(Handshake)** 단계로, 클라이언트와 서버가 **프로토콜 버전****암호화 키**를 교환하고, 서로의 신원을 확인합니다. 두 번째는 **암호화된 데이터 전송** 단계로, 애플리케이션 데이터가 암호화되어 안전하게 통신이 이루어집니다.

## 핸드셰이크 (Handshake)

TLS 핸드셰이크는 클라이언트와 서버 간에 안전한 통신을 설정하기 위한 과정으로, 세션의 암호화 매개변수를 설정하고 TLS 레코드 계층을 통해 안전한 연결을 수립하는 역할을 합니다.

```
Client Server
ClientHello -------->
ServerHello
Certificate*
ServerKeyExchange*
CertificateRequest*
<-------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished -------->
[ChangeCipherSpec]
<-------- Finished
Application Data <-------> Application Data
```

### ClientHello

TLS 핸드셰이크는 클라이언트가 `ClientHello` 메시지를 서버에 전송하면서 시작됩니다. 이 메시지에는 다음 정보가 포함됩니다:

- **TLS 프로토콜 버전**: 클라이언트가 지원하는 TLS 버전. 예를 들어, TLS 1.2 또는 TLS 1.3.
- **암호화 스위트**: 클라이언트가 지원하는 암호화 알고리즘의 목록. 예를 들어, `ECDHE-RSA-AES256-GCM-SHA384`.
- **압축 방법**: 데이터 압축 방식을 명시. TLS 1.3에서는 압축이 비활성화됨.
- **랜덤 값**: 클라이언트가 생성한 임의 데이터로, 핸드셰이크의 보안성을 높이는 데 사용됩니다.

암호화 스위트의 조합은 세션의 보안성을 결정하는 중요한 요소입니다. 다음은 자주 사용되는 알고리즘의 설명입니다:

- **ECDHE (Elliptic Curve Diffie-Hellman Ephemeral)**: 대칭 키를 안전하게 교환하는 알고리즘으로, 각 세션에서 새로운 키를 생성해 보안을 강화합니다.
- **RSA**: 인증서 서명과 키 교환에 사용되는 비대칭 암호화 알고리즘.
- **AES_256_GCM**: 256비트 키를 사용하는 대칭 암호화 알고리즘으로, GCM 모드를 통해 데이터의 기밀성을 보장합니다.
- **SHA384**: 메시지 무결성을 확인하기 위한 해시 함수.

특히 **ECDHE** 알고리즘은 매 세션마다 새로운 키를 생성하여 보안성을 극대화합니다. 이를 통해 비밀 정보를 직접 공유하지 않고도 동일한 공유 비밀 키를 생성할 수 있습니다.

- **공개 파라미터 설정**: 클라이언트와 서버는 소수 \( p \)와 원시 근 \( g \)를 공개적으로 선택합니다.
- **비밀 키 생성**: 클라이언트와 서버는 각자 개인 비밀 키 \( a \)\( b \)를 생성합니다.
- **공개 키 전송**: 생성된 공개 키를 상대방에게 전송합니다.
- **공유 비밀 키 생성**: 상대방의 공개 키를 사용해 공유 비밀 키를 계산합니다.

또한 `ClientHello` 메시지에는 몇 가지 확장 기능이 포함될 수 있습니다:

- **SNI (Server Name Indication)**: 클라이언트가 요청하는 서버의 도메인 이름을 포함하여 서버가 적절한 인증서를 선택할 수 있게 합니다. 이는 여러 도메인을 하나의 IP 주소에서 호스팅할 때 유용합니다.
- **ALPN (Application Layer Protocol Negotiation)**: TLS 핸드셰이크 중 클라이언트와 서버가 사용하려는 애플리케이션 계층 프로토콜을 협상할 수 있게 해줍니다. 클라이언트가 지원하는 프로토콜 목록을 제공하면, 서버는 적합한 프로토콜을 선택하여 응답합니다.

### ServerHello

서버는 클라이언트의 `ClientHello` 메시지에 대한 응답으로 `ServerHello` 메시지를 전송합니다. 이 메시지에는 다음 정보가 포함됩니다:

- **협상된 TLS 프로토콜 버전**: 서버가 지원하는 가장 높은 버전의 TLS.
- **선택된 암호화 스위트**: 클라이언트가 제안한 목록 중 서버가 선택한 암호화 알고리즘 조합.
- **압축 방법**: 서버가 사용할 데이터 압축 방식.
- **서버 랜덤 값**: 서버가 생성한 랜덤 데이터로, 핸드셰이크 과정에서 보안성을 높이는 데 사용됩니다.

이 단계에서 서버는 선택된 암호화 매개변수를 설정하고, 이후 클라이언트와의 안전한 데이터 전송을 준비합니다.

### Certificate

서버는 `Certificate` 메시지를 통해 클라이언트에게 자신을 증명하는 인증서를 전송합니다. 이 인증서는 **X.509 표준**을 따르며, 서버의 공개 키와 신원 정보를 포함합니다. 이를 통해 클라이언트는 서버가 신뢰할 수 있는지 검증할 수 있습니다. 인증서는 신뢰할 수 있는 인증 기관(CA)에 의해 서명되어, 그 진위성과 무결성을 보장합니다.

X.509 인증서의 주요 구성 요소는 다음과 같습니다:

```text
Certificate
- Version: 인증서의 버전
- Serial Number: CA가 할당한 고유 번호
- Algorithm Identifier: 서명에 사용된 알고리즘 식별자
- Signature: 인증서의 디지털 서명
- Issuer: 인증서 발급자(CA)
- Validity: 인증서의 유효 기간
- Not Before: 유효 기간 시작 날짜
- Not After: 유효 기간 종료 날짜
- Subject: 인증서 소유자
- Subject Public Key Info: 공개 키 정보
- Public Key Algorithm: 사용된 공개 키 알고리즘
- Subject Public Key: 소유자의 공개 키
- Issuer Unique Identifier (Optional): 발급자의 고유 식별자
- Subject Unique Identifier (Optional): 소유자의 고유 식별자
- Extensions (Optional): 확장 정보 (예: SAN, Key Usage 등)
Certificate Signature Algorithm: 서명에 사용된 알고리즘
Certificate Signature: 서명 데이터
```

인증 기관(CA)은 서버 인증서를 발급할 때, 인증서 내용에 디지털 서명을 추가하여 이를 보장합니다. 이 서명은 **PKCS#1 v1.5 패딩**과 같은 알고리즘을 사용하여 데이터를 암호화합니다. 인증서에는 도메인 이름이 **Subject** 필드에 명시되며, **SAN (Subject Alternative Name)** 확장을 통해 여러 도메인을 인증할 수 있습니다.

인증 체계는 계층적으로 구성되며, 가장 상위에는 **Root CA**가 있습니다. `Root CA`는 자기 서명(self-signed)된 인증서를 보유하고 있으며, 그 하위에 위치한 **Intermediate CA**에게 인증서를 발급합니다. 이로 인해 신뢰의 연쇄(trust chain)가 형성되며, 최종적으로 서버 또는 클라이언트에 도달하게 됩니다.

- **Root CA**: 신뢰 체계의 최상위에 있는 기관으로, 자기 서명된 인증서를 발급합니다.
- **Intermediate CA**: Root CA의인증을 받은 후 인증서를 발급할 수 있는 기관입니다.
- **Server CA**: 실제 서버에 인증서를 발급하여 통신 보안을 제공합니다.

### ServerKeyExchange

서버는 `ServerKeyExchange` 메시지를 전송하여 클라이언트와 공유할 수 있는 키를 교환합니다. 이 메시지에는 다음 정보가 포함됩니다:

- **서버의 공개 키**: 서버가 사용하는 공개 키, 클라이언트가 암호화된 정보를 서버에 전송할 때 사용됩니다.
- **DH 파라미터**: Diffie-Hellman 키 교환을 위한 파라미터. 이는 클라이언트와 서버 간의 암호화된 키를 생성하는 데 사용됩니다.

### CertificateRequest

서버는 클라이언트의 인증서를 요청할 수 있습니다. 이 메시지에는 다음 정보가 포함됩니다:

- **요청하는 인증서 유형**: 클라이언트 인증에 사용될 인증서의 유형.
- **인증 기관 목록**: 클라이언트가 제공해야 하는 인증서가 발급된 인증 기관의 목록.

클라이언트 인증은 서버가 클라이언트를 신뢰할 수 있는지 확인하기 위해 사용됩니다. 클라이언트 인증서를 통해 클라이언트는 자신의 신원을 증명할 수 있습니다.

### ServerHelloDone

서버는 `ServerHelloDone` 메시지를 전송하여 클라이언트의 응답을 기다립니다. 이 메시지는 서버가 핸드셰이크 과정의 초기 단계를 완료했음을 나타냅니다.

### Certificate

클라이언트는 서버와의 통신을 위한 **인증서**를 전송합니다. 클라이언트 인증서는 클라이언트가 서버에 제공할 신뢰할 수 있는 증명서를 의미합니다.

### ClientKeyExchange

클라이언트는 `ClientKeyExchange` 메시지를 전송하여 서버와 공유할 비밀 키를 전달합니다. 이 메시지에는 클라이언트가 생성한 **프리마스터 시크릿(Pre-Master Secret)**이 포함됩니다. 이 비밀 키는 세션의 암호화 키를 생성하는 데 사용됩니다.

### CertificateVerify

클라이언트는 `CertificateVerify` 메시지를 전송하여 클라이언트 인증서가 유효함을 증명합니다. 이 메시지에는 클라이언트 인증서의 서명이 포함되며, 서버는 이를 통해 클라이언트의 인증서를 검증합니다.

### ChangeCipherSpec

클라이언트와 서버는 `ChangeCipherSpec` 메시지를 전송하여 암호화 매개변수를 변경합니다. 이 메시지는 새로운 암호화 키와 매개변수를 적용할 준비가 되었음을 나타냅니다.

### Finished

클라이언트와 서버는 `Finished` 메시지를 전송하여 핸드셰이크가 완료되었음을 알립니다. 이 메시지는 핸드셰이크 과정에서 교환된 모든 정보가 무결성을 유지하고 있음을 확인하는 역할을 합니다.

## 암호화된 데이터 전송

핸드셰이크가 완료된 후, 클라이언트와 서버는 암호화된 데이터 전송을 시작합니다. TLS는 **TLS 레코드 계층**을 통해 애플리케이션 데이터를 안전하게 암호화합니다.

### 레코드 계층 (Record Layer)

레코드 계층은 암호화된 데이터의 전송을 담당합니다. 이 계층은 전송할 데이터가 적절히 암호화되어 송신되도록 보장하며, 수신된 데이터는 복호화하여 애플리케이션이 처리할 수 있도록 합니다. 레코드 계층의 주요 역할은 다음과 같습니다:

- **데이터 분할 및 재조합**: 애플리케이션 데이터는 TLS 레코드 계층에서 일정 크기로 분할되며, 수신 측에서는 이를 재조합하여 처리합니다.
- **암호화 및 복호화**: 데이터를 송신하기 전에 암호화하고, 수신 측에서는 이를 복호화하여 처리합니다.
- **무결성 검증**: 데이터의 무결성을 확인하기 위해 메시지 인증 코드(MAC)를 사용합니다. 이를 통해 데이터 전송 중 변경되거나 손상된 경우 이를 감지할 수 있습니다.

레코드 계층은 애플리케이션 데이터를 다음 단계로 전달하기 전에 적절하게 암호화하고 무결성을 검증합니다.

TLS는 각 레코드에 **헤더**를 추가하여 데이터 전송 중 오류나 손상을 감지하며, **HMAC** (Hash-based Message Authentication Code)을 사용하여 데이터 무결성을 검증합니다. 송신자는 수신자와 합의한 해시 함수를 이용하여 해시 값을 생성하고, 이를 메시지에 추가하여 전송합니다. 수신자는 메시지와 해시 값을 분리하여, 데이터가 손상되지 않았는지 확인합니다.

## 참고 문서

- [RFC 5246 - The Transport Layer Security](https://datatracker.ietf.org/doc/html/rfc5246)
- [X.509](https://ko.wikipedia.org/wiki/X.509)
- [Luavis' Dev Story - 알아두면 쓸데없는 신비한 TLS](https://luavis.me/server/tls-101)

0 comments on commit 3c290f3

Please sign in to comment.