작성일 :

암호화 없는 터널의 위험

Part 1에서 서울 본사(10.1.0.0/16)와 부산 지사(10.2.0.0/16)를 GRE 터널로 연결하는 방법을 살펴보았습니다. 하지만 GRE에는 암호화가 없었습니다.

암호화 없는 터널에서는 어떤 일이 생길 수 있을까요?


서울에서 부산으로 기밀 문서를 보낸다고 합시다. 패킷이 인터넷을 지나는 동안, 중간 라우터를 장악한 공격자가 패킷을 복사합니다. 터널 안의 내용이 평문이므로 문서 전체를 읽을 수 있습니다. 이것이 도청입니다.

더 심각한 경우도 있습니다. 공격자가 패킷을 복사하는 데서 그치지 않고, 내용을 바꿔서 부산으로 보냅니다. 송금액 1000원을 100만원으로 고칩니다. 부산 지사는 변조된 패킷을 정상으로 받아들입니다. 이것이 변조입니다.

공격자가 서울 본사인 척 위장한 패킷을 만들어 보낼 수도 있습니다. 부산 지사는 이것이 진짜 서울에서 온 것인지 구분할 방법이 없습니다. 이것이 위장입니다.

마지막으로, 공격자가 어제 서울에서 보낸 정상 송금 요청을 캡처해 두었다가 오늘 다시 보냅니다. 같은 송금이 두 번 실행됩니다. 이것이 재전송 공격입니다.


IPsec(IP Security)은 이 네 가지 위협을 모두 막습니다.

패킷 내용을 암호화하여 도청을 막고(기밀성), 변조 여부를 검증하고(무결성), 송신자가 진짜인지 확인하고(인증), 같은 패킷이 다시 오면 거부합니다(재전송 방지).


IPsec의 역사

1990년대 초, 인터넷이 상업적으로 확산되면서 보안 문제가 심각해졌습니다.

원래 IP 프로토콜은 대학과 연구소 사이의 신뢰할 수 있는 네트워크를 전제로 설계되었습니다. “패킷을 목적지까지 전달한다”가 전부였고, “누가 엿보거나 변조하면 어떻게 하지?”라는 질문은 고려 대상이 아니었습니다.

하지만 인터넷이 상업화되면서 상황이 달라졌습니다. 은행 거래, 기업 기밀, 개인 정보가 인터넷을 오가기 시작했고, 보안은 더 이상 선택이 아니었습니다.


이 문제를 해결하기 위해 IETF는 1995년부터 IPsec 표준화 작업을 시작했습니다. 20년 넘게 여러 차례 개정을 거쳤고, 현재 실무에서 참조하는 핵심 문서는 세 가지입니다.

RFC 2401(1998)이 초기 구조를 정의했고, RFC 4301(2005)이 현재 구조로 개정했습니다. RFC 7296(2014)은 키 교환 프로토콜인 IKEv2를 정의합니다.


IPsec의 구성 요소

서울 본사와 부산 지사가 IPsec으로 안전하게 통신하려면, 어떤 일들이 일어나야 할까요?


먼저, 양쪽이 암호화 키를 공유해야 합니다. 서울이 암호화한 패킷을 부산이 복호화하려면, 같은 키를 가지고 있어야 합니다. 하지만 인터넷은 누구나 엿볼 수 있는 공개된 통로입니다. 비밀 키를 그냥 보내면 공격자도 볼 수 있습니다. IKE(Internet Key Exchange)가 이 문제를 해결합니다.

키가 준비되면, 실제로 패킷을 암호화해야 합니다. ESP(Encapsulating Security Payload)가 이 역할을 담당합니다.

암호화는 원본 데이터를 키를 사용해 알아볼 수 없는 형태로 바꾸는 것입니다. 서울 게이트웨이가 패킷을 암호화하면, 인터넷을 지나는 동안 누가 봐도 의미 없는 데이터로 보입니다. 부산 게이트웨이가 같은 키로 복호화하면 원본 패킷이 나옵니다. 키를 모르는 공격자는 복호화할 수 없습니다.

그런데 ESP는 암호화만 하는 게 아닙니다. 패킷 전체를 계산하여 짧은 인증 값(ICV)을 만들고, 이것을 패킷 끝에 붙입니다. 봉투에 봉인 도장을 찍는 것과 비슷합니다. 부산 지사가 패킷을 받으면 같은 계산을 해서 ICV가 일치하는지 확인합니다. 공격자가 중간에서 패킷을 변조하면 ICV가 맞지 않게 되어, “이 패킷은 변조되었다”고 알 수 있습니다.

참고로 AH(Authentication Header)라는 프로토콜도 있지만, 암호화 없이 인증만 하기 때문에 현재는 거의 사용되지 않습니다.

그런데 서울에서 나가는 모든 패킷을 암호화해야 할까요? 부산 지사로 가는 패킷은 암호화하고, Google로 가는 패킷은 그냥 보내고 싶을 수 있습니다. SPD(Security Policy Database)가 “어떤 트래픽에 어떤 처리를 할지” 정책을 저장합니다. 그리고 SAD(Security Association Database)가 현재 활성화된 연결들의 키와 설정을 저장합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
서울 본사 게이트웨이                                       부산 지사 게이트웨이

1. 키 교환 (IKE)
        ├─────────── 알고리즘 제안: AES-256, 키 교환 ──────►│
        │◄─────────── 합의 확인 ────────────────────────────┤

2. 합의 내용 저장 (SAD)
   ┌─────────────────────┐                    ┌─────────────────────┐
   │ 부산과의 연결:       │                    │ 서울과의 연결:       │
   │ AES-256, 키=...     │                    │ AES-256, 키=...     │
   └─────────────────────┘                    └─────────────────────┘

3. 패킷 전송 시
   SPD 조회: 목적지 10.2.0.0/16 → 암호화 정책 적용
        │
        ▼
   ESP로 암호화 ─────────────────────────────────────────► 복호화

IKE: 키 교환 프로토콜

서울 본사와 부산 지사가 암호화 통신을 하려면, 먼저 암호화에 사용할 비밀 키를 공유해야 합니다.

하지만 문제가 있습니다. 인터넷은 누구나 엿볼 수 있는 공개된 통로입니다. 비밀 키를 인터넷으로 그냥 보내면, 공격자도 그 키를 볼 수 있습니다. 그렇다고 USB에 담아서 택배로 보낼 수도 없습니다.

IKE(Internet Key Exchange)는 이 문제를 해결하는 키 교환 프로토콜입니다. 공개된 네트워크에서도 안전하게 비밀 키를 교환할 수 있으며, UDP 포트 500을 사용합니다.


IKEv1 vs IKEv2

IKE에는 버전 1과 버전 2가 있습니다. 서울 본사와 부산 지사의 VPN 장비가 서로 다른 벤더 제품일 때, 버전 선택이 연결 성공 여부를 좌우할 수 있습니다.


IKEv1(1998)은 2단계로 키를 협상합니다.

1
2
3
4
5
6
7
8
9
10
Phase 1: 보안 채널 수립                        (6 메시지)
         - 메시지 1-2: 알고리즘 협상
         - 메시지 3-4: DH 키 교환
         - 메시지 5-6: 상호 인증
    │
    ▼
Phase 2: 실제 데이터 암호화용 SA 협상           (3 메시지)
         - 메시지 1: SA 제안 + 키 재료
         - 메시지 2: SA 선택 + 키 재료
         - 메시지 3: 확인

총 9개의 메시지를 주고받아야 협상이 완료됩니다. 구조는 논리적이지만, 실무에서 문제가 많았습니다. 각 단계마다 여러 교환 모드가 있고, 암호화 알고리즘, 해시 알고리즘, DH 그룹, 인증 방식 등을 각각 선택해야 합니다. 옵션 조합이 수십 가지에 달합니다.

양쪽 장비의 옵션이 하나라도 다르면 터널이 수립되지 않습니다. 메시지 교환 단계가 많아 어느 지점에서 실패했는지 파악하기도 어렵습니다.


IKEv2(2005, 현재 버전은 RFC 7296)는 이 복잡함을 해결하기 위해 설계되었습니다.

1
2
3
4
5
6
7
8
IKE_SA_INIT:                                    (2 메시지)
         - 메시지 1: 알고리즘 제안 + DH 공개값
         - 메시지 2: 알고리즘 선택 + DH 공개값
    │
    ▼
IKE_AUTH:                                       (2 메시지)
         - 메시지 3: 인증 + SA 제안
         - 메시지 4: 인증 + SA 선택

4개의 메시지로 협상이 완료됩니다. IKEv1에서 9개였던 메시지가 절반 이하로 줄었습니다. 교환 모드 구분이 없어지고 옵션 조합이 단순해져서, 설정 불일치로 인한 연결 실패가 줄었습니다.

IKEv2는 NAT 환경을 자동으로 감지하고 처리합니다. 이를 NAT-T(NAT Traversal)라고 합니다.

NAT 장비는 내부의 여러 호스트가 하나의 공인 IP를 공유할 수 있게 해줍니다. 이때 각 연결을 구분하는 기준이 포트 번호입니다. 내부 호스트 A가 포트 12345로, 호스트 B가 포트 12346으로 통신하면, NAT 장비는 이 포트 번호를 보고 응답 패킷을 올바른 호스트에게 전달합니다.

그런데 ESP 패킷에는 포트 번호가 없습니다. ESP는 IP 바로 위에서 동작하는 프로토콜(IP 프로토콜 번호 50)이기 때문입니다. NAT 장비 입장에서는 ESP 패킷이 들어오면 어느 내부 호스트에게 전달해야 할지 알 수 없습니다.

1
2
3
4
5
6
7
TCP/UDP 패킷:  [IP 헤더][TCP/UDP 헤더 (포트 번호 있음)][데이터]
                              ↑
                    NAT가 이 포트로 호스트 구분

ESP 패킷:      [IP 헤더][ESP 헤더 (포트 번호 없음)][암호화된 데이터]
                              ↑
                    NAT가 구분할 방법 없음

NAT-T는 이 문제를 해결합니다. ESP 패킷을 UDP로 감싸서 포트 번호를 부여합니다. NAT 장비는 이제 UDP 포트 번호를 보고 패킷을 올바른 호스트에게 전달할 수 있습니다.

1
2
3
4
5
6
7
원본:       [IP 헤더][ESP 헤더][암호화된 데이터]
                          │
                    UDP로 캡슐화
                          ▼
NAT-T:      [IP 헤더][UDP 헤더 (4500)][ESP 헤더][암호화된 데이터]
                          ↑
                NAT가 이 포트로 호스트 구분

포트 4500을 사용하는 이유가 있습니다. IKE는 원래 UDP 포트 500을 사용하는데, 일부 NAT 장비는 포트 500에 대해 특수 처리(IKE passthrough)를 합니다. 이 특수 처리가 오히려 패킷을 손상시키거나 간섭을 일으킬 수 있습니다. 포트 4500은 NAT-T 전용으로 지정되어 있어 이런 문제를 피할 수 있습니다.

DPD(Dead Peer Detection) 기능도 내장되어 있습니다.

서울 본사와 부산 지사 간에 VPN 터널이 수립된 상황을 생각해봅시다. 부산 지사 게이트웨이가 갑자기 재부팅되었습니다. 부산 쪽 SAD가 초기화되면서 그 안에 저장된 SA가 모두 사라집니다. 하지만 서울 본사 게이트웨이는 이 사실을 알 수 없습니다. 서울 쪽 SAD에는 여전히 SA가 남아 있고, 이 SA로 패킷을 암호화해서 보냅니다. 부산에서는 해당 SPI에 대응하는 SA를 SAD에서 찾을 수 없어 패킷을 복호화할 수 없습니다.

1
2
3
4
5
6
7
8
9
서울 본사                                          부산 지사
    │                                                  │
    │  SAD에 SA 유지 중                    (재부팅) SAD 초기화
    │                                                  │
    ├──── 암호화된 패킷 (SPI=1001) ────────────────────►│
    │                                                  │
    │                                     SAD에서 SPI=1001 조회 실패
    │                                                  │
    │                                              패킷 폐기

DPD는 이 문제를 해결합니다. 일정 시간 동안 상대방으로부터 트래픽이 없으면, 확인 메시지를 보냅니다. 상대방이 정상이면 응답이 돌아오고, 재부팅되었거나 장애 상태면 응답이 없습니다.

1
2
3
4
5
6
7
8
9
10
11
서울 본사                                          부산 지사
    │                                                  │
    ├──── DPD 확인 메시지 ─────────────────────────────►│ (응답 없음)
    │                                                  │
    │  응답 대기...                                     │
    │                                                  │
    │  타임아웃 → 상대방 장애로 판단                     │
    │                                                  │
    │  SAD에서 해당 SA 삭제                             │
    │                                                  │
    ├──── 새로운 IKE 협상 시작 ────────────────────────►│

서울 본사 게이트웨이는 응답이 없으면 SAD에서 해당 SA를 삭제하고, 새로운 IKE 협상을 시작합니다. 부산 지사 게이트웨이가 복구되었다면, 새로운 SA가 수립되어 통신이 재개됩니다.

IKEv1에서는 DPD를 별도로 설정해야 했습니다. IKEv2에서는 기본 내장되어 있어 별도 설정 없이 동작합니다. 이러한 이유로 현재 신규 구축에서는 IKEv2 사용이 권장됩니다.


IKEv2 초기 교환

서울 본사 게이트웨이가 부산 지사 게이트웨이와 IPsec 터널을 수립하는 과정입니다.

1단계: IKE_SA_INIT (암호화 알고리즘 협상 + DH 키 교환)

1
2
3
4
5
6
7
8
9
10
11
12
서울 본사 (203.0.113.5)                              부산 지사 (198.51.100.5)
         │                                                    │
         │ ──── IKE_SA_INIT 요청 ─────────────────────────► │
         │      - 암호화 알고리즘 제안: AES-256               │
         │      - DH 그룹 제안: Group 14                      │
         │      - DH 공개값 전송                              │
         │                                                    │
         │ ◄──── IKE_SA_INIT 응답 ─────────────────────────  │
         │      - 암호화 알고리즘 선택: AES-256               │
         │      - DH 공개값 전송                              │
         │                                                    │
         │      [양쪽 모두 DH 계산으로 동일한 비밀 키 도출]   │

이 시점에서 양쪽은 동일한 비밀 키를 가지게 됩니다. 이후 메시지는 이 키로 암호화됩니다.

2단계: IKE_AUTH (상호 인증 + SA 수립)

1
2
3
4
5
6
7
8
9
10
11
12
13
서울 본사                                            부산 지사
         │                                                    │
         │ ──── IKE_AUTH 요청 (암호화됨) ─────────────────► │
         │      - 서울 본사 신원 정보                         │
         │      - 인증서 또는 사전 공유 키로 인증             │
         │      - IPsec SA 제안                               │
         │                                                    │
         │ ◄──── IKE_AUTH 응답 (암호화됨) ─────────────────  │
         │      - 부산 지사 신원 정보                         │
         │      - 인증서 또는 사전 공유 키로 인증             │
         │      - IPsec SA 선택                               │
         │                                                    │
         │      [IPsec 터널 수립 완료 - SAD에 SA 저장]        │

4개의 메시지로 협상이 완료됩니다. IKE_SA_INIT에서 암호화 키를 합의하고, IKE_AUTH에서 서로의 신원을 확인한 뒤 IPsec SA를 수립합니다. 수립된 SA는 양쪽 SAD에 저장됩니다.


공유 비밀 계산: 어떻게 공개된 통로에서 비밀을 공유하는가

IKE_SA_INIT에서 양쪽이 “DH 공개값”을 교환한다고 했습니다. 이게 어떻게 안전할까요?

IKE는 네트워크 보안에서 설명한 Diffie-Hellman(DH) 알고리즘을 사용합니다.

핵심 아이디어는 이렇습니다. 서울과 부산이 각자 비밀 숫자를 하나씩 정합니다. 이 숫자 자체는 절대 인터넷에 보내지 않습니다. 대신 이 숫자로 “공개 값”을 계산해서 서로 교환합니다.


1
2
3
4
5
6
7
8
9
서울 본사                                           부산 지사
비밀 값: a (절대 전송 안 함)                       비밀 값: b (절대 전송 안 함)
    │                                                   │
    │  공개 값: g^a  ────────────────────────────────►  │
    │  ◄────────────────────────────────  공개 값: g^b  │
    │                                                   │
    │  계산: (g^b)^a = g^ab                 계산: (g^a)^b = g^ab
    │                                                   │
    └─────────── 양쪽 모두 동일한 g^ab를 얻음 ──────────┘

공격자가 중간에서 g^a와 g^b를 모두 캡처하더라도, a나 b를 알아내는 것은 수학적으로 현실적인 시간 안에 불가능합니다. 이것이 DH 안전성의 근거입니다.

이렇게 계산한 공유 비밀(g^ab)은 그 자체로 암호화 키가 되지 않습니다. 대신, 이 값을 입력으로 키 파생 함수(KDF)를 실행하여 암호화 키, 인증 키 등 필요한 여러 키를 생성합니다. 하나의 공유 비밀에서 용도별로 분리된 키들을 만들어 보안을 강화합니다.


SA: Security Association

IKE 협상이 끝나면, 서울 본사와 부산 지사는 합의에 도달합니다. “우리는 AES-256으로 암호화하고, SHA-256으로 무결성을 검증하고, 이 키를 사용하고, 1시간마다 키를 갱신한다.”

이 합의 내용을 저장한 것이 SA(Security Association)입니다. 앞서 KDF로 파생한 키들과 협상한 알고리즘 정보가 여기에 담깁니다. 계약서처럼 양쪽이 동일한 내용을 각자 보관합니다.


1
2
3
4
5
6
7
8
9
10
서울 본사가 보관한 SA (서울→부산)       부산 지사가 보관한 SA (서울→부산)
┌──────────────────────────────┐    ┌──────────────────────────────┐
│ 방향: 서울 → 부산            │    │ 방향: 서울 → 부산            │
│ 암호화: AES-256-GCM          │    │ 암호화: AES-256-GCM          │
│ 무결성: SHA-256              │    │ 무결성: SHA-256              │
│ 암호화 키: 0xABCD...         │ == │ 암호화 키: 0xABCD...         │
│ 인증 키: 0x1234...           │ == │ 인증 키: 0x1234...           │
│ 수명: 3600초                 │    │ 수명: 3600초                 │
│ 모드: Tunnel                 │    │ 모드: Tunnel                 │
└──────────────────────────────┘    └──────────────────────────────┘

서울에서 부산으로 패킷을 보낼 때, 서울 게이트웨이는 이 SA를 참조하여 암호화합니다. 부산 게이트웨이는 같은 SA를 참조하여 복호화합니다. 양쪽이 동일한 키와 알고리즘을 알고 있으므로 통신이 가능합니다.


SA의 단방향 특성

앞서 본 SA에는 “방향: 서울 → 부산”이라고 적혀 있었습니다. SA는 단방향입니다. 서울→부산 방향과 부산→서울 방향은 별개의 SA입니다.

왜 이렇게 설계했을까요?

양방향을 하나의 SA로 묶으면 간단해 보입니다. 하지만 보안상 문제가 있습니다. 하나의 키로 양방향 암호화를 하면, 그 키가 유출되었을 때 과거와 미래의 모든 통신이 노출됩니다. 방향별로 키를 분리하면, 서울→부산 키가 유출되어도 부산→서울 통신은 여전히 안전합니다.

1
2
3
4
5
6
7
8
9
10
서울 본사                                          부산 지사
(203.0.113.5)                                      (198.51.100.5)
     │                                                  │
     │ ─────────── SA 1: 서울→부산 ──────────────────► │
     │            암호화 키: 0xABCD...                  │
     │            인증 키: 0x1234...                    │
     │                                                  │
     │ ◄─────────── SA 2: 부산→서울 ───────────────── │
     │            암호화 키: 0xEFGH...                  │
     │            인증 키: 0x5678...                    │

KDF가 하나의 공유 비밀에서 네 개의 키를 파생하는 이유가 여기에 있습니다. 방향별로, 용도별로 키를 분리하여 보안을 강화합니다.

따라서 양방향 통신을 위해서는 두 개의 SA가 필요합니다.


SPI: 어떤 SA를 사용할지 알려주는 번호표

부산 지사 게이트웨이가 여러 사이트와 IPsec 터널을 맺고 있다고 합시다. 서울 본사, 대전 지사, 광주 지사… 각각 별도의 SA가 있습니다. 게다가 SA는 단방향이므로, 서울과의 연결만 해도 두 개의 SA(서울→부산, 부산→서울)가 있습니다.

패킷이 도착했을 때, 이 패킷이 어느 SA에 해당하는지 어떻게 알 수 있을까요?

SPI(Security Parameter Index)가 이 역할을 합니다. 32비트 숫자로, 각 SA에 고유하게 부여됩니다. 패킷 앞에 SPI가 붙어서 “나는 이 SA에 해당하는 패킷이야”라고 알려줍니다.

1
2
3
4
5
6
7
8
9
서울에서 온 패킷 (서울→부산 방향):
┌─────────────────┬────────────────────────────────┐
│ SPI: 0x00001001 │        암호화된 데이터         │
└─────────────────┴────────────────────────────────┘

부산 게이트웨이:
  SPI = 0x00001001 → SA 테이블 조회 → "서울→부산 SA구나"
  → 암호화 키(0xABCD...)로 복호화
  → 인증 키(0x1234...)로 무결성 검증

SAD와 SPD

SA가 “서울-부산 연결의 계약서”라면, 이 계약서들을 어디에 보관할까요? 그리고 “어떤 패킷에 어떤 계약을 적용할까?”는 어떻게 결정할까요?

SAD: 현재 활성화된 연결 목록

SAD(Security Association Database)는 현재 활성화된 모든 SA를 저장합니다. 앞서 본 SPI로 조회하면 해당 SA의 정보를 찾을 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
부산 지사 게이트웨이의 SAD:
┌───────────┬─────────────┬────────────┬───────────────┬───────────────┐
│    SPI    │    방향     │  알고리즘   │   암호화 키    │    인증 키    │
├───────────┼─────────────┼────────────┼───────────────┼───────────────┤
│0x00001001 │ 서울→부산   │AES-256-GCM │ 0xABCD...     │ 0x1234...     │
├───────────┼─────────────┼────────────┼───────────────┼───────────────┤
│0x00001002 │ 부산→서울   │AES-256-GCM │ 0xEFGH...     │ 0x5678...     │
├───────────┼─────────────┼────────────┼───────────────┼───────────────┤
│0x00002001 │ 대전→부산   │AES-256-GCM │ 0xIJKL...     │ 0x9ABC...     │
├───────────┼─────────────┼────────────┼───────────────┼───────────────┤
│0x00002002 │ 부산→대전   │AES-256-GCM │ 0xMNOP...     │ 0xDEF0...     │
└───────────┴─────────────┴────────────┴───────────────┴───────────────┘

서울과의 연결에 SA가 두 개(서울→부산, 부산→서울), 대전과의 연결에도 SA가 두 개입니다. SA가 단방향이기 때문입니다.


SPD: 어떤 트래픽에 암호화를 적용할까

SPD(Security Policy Database)는 정책을 정의합니다. “이 조건에 맞는 트래픽은 이렇게 처리해라”라는 규칙 목록입니다.

서울 본사 게이트웨이의 SPD를 봅시다.

1
2
3
4
5
6
7
8
9
10
11
12
13
서울 본사 게이트웨이의 SPD:
┌─────────────────────────┬─────────────────┬─────────────────┐
│         조건            │      동작       │    사용할 SA    │
├─────────────────────────┼─────────────────┼─────────────────┤
│ 10.1.0.0/16 →          │    PROTECT      │ 서울→부산 SA    │
│ 10.2.0.0/16 (부산 지사) │  (암호화 적용)  │ (SPI 0x00001001)│
├─────────────────────────┼─────────────────┼─────────────────┤
│ 10.1.0.0/16 →          │    BYPASS       │        -        │
│ 8.8.8.8 (Google DNS)   │ (암호화 안 함)  │                 │
├─────────────────────────┼─────────────────┼─────────────────┤
│ 기타 모든 트래픽        │    DISCARD      │        -        │
│                         │    (폐기)       │                 │
└─────────────────────────┴─────────────────┴─────────────────┘

본사 직원(10.1.0.5)이 부산 지사 서버(10.2.0.5)에 접속하면 어떻게 될까요? 첫 번째 규칙에 매칭됩니다. 게이트웨이는 SAD에서 SPI 0x00001001에 해당하는 SA를 찾아 암호화 키(0xABCD…)로 패킷을 암호화합니다.

본사 직원이 Google DNS(8.8.8.8)에 질의하면? 두 번째 규칙에 매칭되어 암호화 없이 그냥 나갑니다.

그 외의 트래픽은? 세 번째 규칙에 매칭되어 폐기됩니다.


ESP: 실제 암호화를 담당하는 프로토콜

지금까지 IKE로 키를 교환하고, KDF로 암호화 키와 인증 키를 파생하고, SA에 저장하고, SAD와 SPD로 관리하는 방법을 살펴봤습니다. 이제 실제로 패킷을 암호화하는 부분을 봅시다.

ESP(Encapsulating Security Payload)가 이 역할을 담당합니다. IP 프로토콜 번호 50을 사용합니다. TCP가 6번, UDP가 17번인 것처럼, ESP는 50번입니다.

글 앞부분에서 IPsec이 네 가지 위협을 막는다고 했습니다. 도청(기밀성), 변조(무결성), 위장(인증), 재전송 공격(재전송 방지). ESP는 이 중 세 가지를 직접 구현합니다.

  • 기밀성: 암호화 키(0xABCD…)로 데이터를 암호화하여 도청을 막습니다.
  • 무결성: 인증 키(0x1234…)로 ICV(Integrity Check Value)를 계산하여 변조를 탐지합니다.
  • 재전송 방지: 시퀀스 번호로 같은 패킷이 다시 오면 거부합니다.

나머지 하나인 인증(송신자가 진짜인지 확인)은 IKE 단계에서 처리됩니다. 인증서나 사전 공유 키로 상대방 신원을 확인한 후에야 SA가 수립되기 때문입니다.


ESP 패킷 구조

서울 본사에서 부산 지사로 보내는 ESP 패킷의 구조를 봅시다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
서울 → 부산 ESP 패킷 (서울→부산 SA 사용):
┌─────────────────────────────────────────────────────────────┐
│                     ESP 헤더 (8바이트)                       │
├──────────────────────────────┬──────────────────────────────┤
│  SPI: 0x00001001             │  Sequence Number: 42         │
│  (서울→부산 SA)              │  (42번째 패킷)               │
├──────────────────────────────┴──────────────────────────────┤
│                                                             │
│                    암호화된 페이로드                         │
│      (원본: 10.1.0.5 → 10.2.0.5, TCP, 데이터...)           │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│  Padding (블록 크기 맞춤)  │ Pad Length │ Next Header       │
├─────────────────────────────────────────────────────────────┤
│                   ICV (Integrity Check Value)               │
│                  (이 패킷이 변조되지 않았음을 증명)          │
└─────────────────────────────────────────────────────────────┘

       ◄─────────── 암호화 범위 ───────────►
                    (암호화 키 0xABCD...로 암호화)

       ◄──────────────────── 인증 범위 ────────────────────►
                    (인증 키 0x1234...로 ICV 계산)

SPI(0x00001001)는 부산 게이트웨이가 SAD에서 서울→부산 SA를 찾는 데 사용됩니다. 부산은 이 SA에 저장된 암호화 키로 페이로드를 복호화하고, 인증 키로 ICV를 검증합니다. ICV가 맞지 않으면 패킷이 변조된 것이므로 폐기합니다.


Sequence Number: 재전송 공격 방지

앞서 본 ESP 패킷에는 시퀀스 번호 42가 붙어 있었습니다. 이 번호는 서울→부산 SA에서 42번째로 보내는 패킷이라는 의미입니다. 서울 게이트웨이는 패킷을 보낼 때마다 이 번호를 1씩 증가시킵니다.

이 시퀀스 번호가 왜 필요할까요?

공격자가 어제 서울에서 부산으로 보낸 송금 요청 패킷을 캡처했다고 합시다. 패킷은 암호화되어 있어서 내용을 바꿀 수는 없습니다. 하지만 “같은 패킷을 다시 보내는 것”은 가능합니다. 이것이 재전송 공격(Replay Attack)입니다.

부산 게이트웨이는 Anti-replay Window를 유지하여 이 공격을 막습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
부산 게이트웨이의 Anti-replay Window (서울→부산 SA):

현재까지 수신한 최대 시퀀스 번호: 100
윈도우 크기: 64
윈도우 범위: 37 ~ 100

시퀀스 번호 101번 패킷 도착:
  → 윈도우보다 큼 → 정상 수신, 윈도우 갱신 (38~101)

시퀀스 번호 50번 패킷 도착:
  → 윈도우 범위 안에 있음 (37~100)
  → 50번을 이미 받았는지 확인 → 이미 받았음 → 폐기!

시퀀스 번호 30번 패킷 도착:
  → 윈도우 범위 밖 (37보다 작음) → 무조건 폐기!

공격자가 어제 캡처한 패킷의 시퀀스 번호가 42였다면, 오늘 이 패킷을 다시 보내도 윈도우 범위 밖이거나 이미 수신 처리된 번호입니다. 부산 게이트웨이는 이를 재전송으로 판단하고 폐기합니다.


AH: 무결성만 검증하는 프로토콜 (현재는 거의 사용 안 함)

AH(Authentication Header)는 암호화 없이 무결성 검증만 제공하는 프로토콜입니다. IP 프로토콜 번호 51을 사용합니다.

“암호화는 안 하고 무결성만?” 의문이 들 수 있습니다. AH는 “데이터 내용은 공개해도 되지만, 변조는 막아야 하는” 상황을 위해 설계되었습니다.

하지만 현재 실무에서 AH는 거의 사용되지 않습니다. 세 가지 이유가 있습니다.


첫째, ESP가 무결성 검증도 포함합니다. 앞서 본 것처럼 ESP는 인증 키(0x1234…)로 ICV를 계산하여 무결성을 검증합니다. AH가 할 수 있는 모든 것을 ESP도 할 수 있습니다. 암호화가 필요 없다면 ESP에서 암호화를 비활성화(NULL 암호화)하고 무결성 검증만 사용할 수도 있습니다.

둘째, NAT와 호환되지 않습니다. AH는 IP 헤더 전체(출발지/목적지 주소 포함)를 무결성 검증 범위에 포함합니다. Part 1에서 NAT가 IP 주소를 변환한다고 했습니다. NAT가 IP 주소를 바꾸면 AH의 검증 값이 맞지 않게 되고, 패킷은 “변조되었다”고 판단되어 폐기됩니다. 오늘날 대부분의 네트워크가 NAT를 사용하므로 이는 치명적입니다.

셋째, 암호화 없이 무결성만 필요한 경우가 드뭅니다. “내용은 공개해도 되지만 변조는 막아야 한다”라는 상황이 현실에서 얼마나 있을까요? 보안이 필요하다면 대부분 암호화도 함께 적용합니다.

이러한 이유로 현재 대부분의 IPsec 구현에서는 ESP만 사용합니다.


Transport Mode vs Tunnel Mode

IPsec은 패킷을 처리하는 방식에 따라 두 가지 모드로 동작합니다. 둘의 차이는 “무엇을 암호화하는가”입니다.


Transport Mode: 내용만 암호화

원본 IP 헤더는 그대로 두고, 페이로드(TCP/UDP 헤더와 데이터)만 암호화합니다.

서울 본사의 서버 A(10.1.0.10)와 서버 B(10.1.0.20)가 같은 네트워크 안에서 암호화 통신을 하는 경우를 봅시다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
원본 패킷:
┌─────────────────┬─────────────┬───────────┐
│    IP 헤더      │  TCP 헤더   │   데이터   │
│ 10.1.0.10 →    │             │           │
│ 10.1.0.20      │             │           │
└─────────────────┴─────────────┴───────────┘

Transport Mode ESP:
┌─────────────────┬────────────┬─────────────────────┬─────┐
│    IP 헤더      │ ESP 헤더   │ TCP 헤더 + 데이터    │ ICV │
│ 10.1.0.10 →    │ (SPI,      │    (암호화됨)        │     │
│ 10.1.0.20      │  Seq#)     │                     │     │
│ (그대로 노출)   │            │                     │     │
└─────────────────┴────────────┴─────────────────────┴─────┘
                               ◄── 암호화 범위 ──►
                  ◄─────────── 무결성 검증 범위 ───────────►

IP 주소는 그대로 보입니다. “10.1.0.10에서 10.1.0.20으로 뭔가를 보냈다”는 것은 알 수 있지만, “무엇을 보냈는지”는 모릅니다. 수신 측은 ESP 헤더의 SPI로 SA를 찾아 복호화하고, ICV로 무결성을 검증합니다.

새 IP 헤더를 추가하지 않으므로 오버헤드가 적습니다. 하지만 IP 주소가 노출되므로, 보통 같은 네트워크 안에서 호스트 간 직접 통신을 보호하는 용도로 사용됩니다.


Tunnel Mode: 패킷 전체를 암호화

원본 패킷 전체(IP 헤더 포함)를 캡슐화하고, 터널 양 끝점의 IP 주소를 담은 새 IP 헤더를 추가합니다.

서울 본사(10.1.0.0/16)에서 부산 지사(10.2.0.0/16)로 패킷을 보내는 경우를 봅시다. 지금까지 살펴본 서울→부산 SA(SPI 0x00001001)가 사용됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
원본 패킷:
┌─────────────────┬─────────────┬───────────┐
│    IP 헤더      │  TCP 헤더   │   데이터   │
│ 10.1.0.5 →     │             │           │
│ 10.2.0.5       │             │           │
│ (사설 IP)      │             │           │
└─────────────────┴─────────────┴───────────┘

Tunnel Mode ESP (서울→부산 SA 사용):
┌─────────────────┬────────────┬─────────────────────────────────┬─────┐
│   새 IP 헤더    │ ESP 헤더   │  원본 IP 헤더 + TCP 헤더 + 데이터 │ ICV │
│ 203.0.113.5 →  │ (SPI       │         (모두 암호화됨)          │     │
│ 198.51.100.5   │ 0x00001001,│                                 │     │
│ (게이트웨이)    │  Seq#)     │                                 │     │
└─────────────────┴────────────┴─────────────────────────────────┴─────┘
                               ◄────── 암호화 범위 ──────►
                  ◄──────────── 무결성 검증 범위 ─────────────────►

인터넷에서 보이는 것은 “서울 게이트웨이(203.0.113.5)에서 부산 게이트웨이(198.51.100.5)로 뭔가를 보냈다”뿐입니다. 내부 IP 주소(10.1.0.5 → 10.2.0.5)는 암호화되어 보이지 않습니다.

부산 게이트웨이는 SPI(0x00001001)로 SAD에서 서울→부산 SA를 찾고, 암호화 키(0xABCD…)로 복호화하여 원본 패킷을 꺼냅니다. 그런 다음 원본 IP 헤더의 목적지(10.2.0.5)를 보고 부산 지사 내부 네트워크로 전달합니다.

새 IP 헤더가 추가되어 오버헤드가 Transport Mode보다 크지만, 게이트웨이 뒤에 있는 전체 네트워크를 한꺼번에 보호할 수 있습니다.


대부분의 VPN 환경에서는 Tunnel Mode를 사용합니다. Site-to-Site VPN도, Remote Access VPN도 일반적으로 Tunnel Mode입니다. 원본 패킷이 완전히 암호화되어 내부 네트워크 구조가 외부에 노출되지 않기 때문입니다.


NAT와 IPsec

앞서 AH가 NAT 환경과 호환되지 않는다고 했습니다. AH는 IP 헤더 전체를 무결성 검증 범위에 포함하기 때문에, NAT가 IP 주소를 바꾸면 검증에 실패합니다.

그런데 ESP도 NAT와 문제가 있습니다. NAT는 TCP/UDP의 포트 번호를 보고 “이 응답은 내부의 누구에게 전달할지”를 결정합니다.

ESP는 IP 프로토콜 번호 50을 사용하는 별도의 프로토콜이며, 포트 개념이 없습니다. Part 1에서 GRE가 같은 이유로 NAT와 문제가 있었던 것과 동일한 상황입니다.

1
2
3
4
5
6
7
8
9
서울 본사에 두 대의 VPN 게이트웨이가 NAT 뒤에 있다고 합시다:

게이트웨이 A (10.1.0.1) ─┐
                        ├─► NAT (203.0.113.5) ─► 인터넷 ─► 부산 지사
게이트웨이 B (10.1.0.2) ─┘

부산에서 ESP 응답이 돌아올 때:
  - TCP/UDP라면: 포트 번호로 "이건 게이트웨이 A, 이건 게이트웨이 B" 구분 가능
  - ESP라면: 포트 없음 → NAT가 누구에게 전달해야 할지 모름

또 다른 문제도 있습니다. TCP/UDP 헤더에는 체크섬(Checksum)이라는 값이 있습니다. 체크섬은 패킷의 바이트들을 합산하여 만든 짧은 검증 값으로, 수신 측이 같은 계산을 해서 값이 일치하면 “전송 중 데이터가 손상되지 않았다”고 판단합니다. 이 계산에는 출발지/목적지 IP 주소도 포함됩니다.

NAT가 IP 주소를 변경하면 체크섬이 맞지 않게 됩니다. 보통 NAT는 체크섬을 다시 계산해서 수정하지만, ESP로 암호화된 상태에서는 내부 TCP/UDP 헤더에 접근할 수 없으므로 체크섬을 수정할 수 없습니다.


NAT-T: ESP를 UDP로 감싸기

이 문제를 해결하기 위해 NAT-T(NAT-Traversal)가 RFC 3948로 표준화되었습니다.

해결 아이디어는 단순합니다. ESP 패킷을 UDP로 한 번 더 감싸는 것입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
일반 ESP:
┌──────────────┬──────────────────────────────┐
│   IP 헤더    │         ESP 패킷             │
│   (프로토콜  │    (포트 번호 없음!)          │
│     50)      │                              │
└──────────────┴──────────────────────────────┘

NAT-T (ESP over UDP):
┌──────────────┬──────────────┬──────────────────────────────┐
│   IP 헤더    │  UDP 헤더    │         ESP 패킷             │
│  (프로토콜   │ (포트 4500)  │                              │
│    17)       │              │                              │
└──────────────┴──────────────┴──────────────────────────────┘

ESP 패킷이 UDP로 감싸지면, NAT 장비가 일반적인 UDP 트래픽처럼 처리할 수 있습니다.

1
2
3
4
5
6
7
8
9
게이트웨이 A (10.1.0.1)가 포트 4500으로 패킷 전송
  → NAT가 출발지를 203.0.113.5:12345로 매핑

게이트웨이 B (10.1.0.2)가 포트 4500으로 패킷 전송
  → NAT가 출발지를 203.0.113.5:12346으로 매핑

부산에서 응답이 돌아올 때:
  → 목적지 포트 12345 → NAT가 게이트웨이 A로 전달
  → 목적지 포트 12346 → NAT가 게이트웨이 B로 전달

IKEv2는 협상 과정에서 NAT 존재 여부를 자동으로 감지하고, NAT가 있으면 자동으로 NAT-T를 활성화합니다.


IPsec VPN 설정 예시

지금까지 설명한 개념들이 실제 설정에서 어떻게 나타나는지 봅시다. 서울 본사와 부산 지사를 연결하는 IPsec VPN을 설정한다고 합시다.


Phase 1: IKE SA 수립

앞서 IKEv2의 IKE_SA_INIT와 IKE_AUTH 단계를 설명했습니다. Phase 1은 이 과정에 필요한 파라미터를 정의합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Phase 1 (IKE SA) 설정:
┌───────────────────────────────────────────────┐
│ 인증 방법: PSK (Pre-Shared Key)              │
│   → IKE_AUTH에서 상대방 신원 확인에 사용      │
│                                              │
│ DH 그룹: Group 14 (2048비트)                 │
│   → IKE_SA_INIT에서 공유 비밀 계산에 사용     │
│                                              │
│ 암호화: AES-256                              │
│ 무결성: SHA-256                              │
│   → IKE_AUTH 메시지 보호에 사용              │
│                                              │
│ 수명: 86400초 (24시간)                       │
│   → 이 시간이 지나면 IKE SA 재협상            │
└───────────────────────────────────────────────┘

인증 방법으로 PSK(사전 공유 키)가 간편합니다. 서울과 부산이 같은 비밀번호를 미리 공유하고, IKE_AUTH 단계에서 이 비밀번호를 알고 있는지 확인합니다. 수십 개의 지사가 있다면 각각 다른 비밀번호를 관리해야 하므로, 대규모 환경에서는 인증서 기반 인증이 유리합니다.


Phase 2: IPsec SA 수립

Phase 1이 끝나면 IKE SA가 생깁니다. 이제 이 보안 채널 위에서 실제 데이터 보호용 IPsec SA를 협상합니다. 앞서 설명한 서울→부산 SA(SPI 0x00001001)와 부산→서울 SA(SPI 0x00001002)가 이 단계에서 생성됩니다.

1
2
3
4
5
6
7
8
9
10
Phase 2 (IPsec SA) 설정:
┌───────────────────────────────────────────────┐
│ 프로토콜: ESP                                 │
│ 암호화: AES-256-GCM                          │
│   → 암호화 키(0xABCD...)로 데이터 암호화      │
│ 무결성: (GCM 모드에 내장)                     │
│   → 인증 키(0x1234...)로 ICV 계산            │
│ PFS: DH Group 14                             │
│ 수명: 3600초 (1시간)                         │
└───────────────────────────────────────────────┘

수명이 Phase 1(24시간)보다 짧습니다(1시간). Phase 2 SA의 키가 유출되면, 그 키로 암호화된 모든 트래픽이 노출됩니다. 수명을 1시간으로 설정하면, 최악의 경우에도 1시간 분량의 트래픽만 노출됩니다. 1시간이 지나면 새로운 키를 협상하여 SA를 갱신합니다.

PFS(Perfect Forward Secrecy)는 과거 트래픽을 보호합니다. 구체적인 시나리오로 설명하겠습니다.

공격자가 서울-부산 간 암호화된 트래픽을 1년간 저장해두었다고 합시다. 트래픽은 암호화되어 있어서 당장은 읽을 수 없습니다. 그런데 1년 후, 공격자가 서울 게이트웨이를 해킹하여 개인키를 탈취했습니다.

PFS 없이: Phase 1의 공유 비밀(g^ab)에서 모든 Phase 2 키가 파생됩니다. 공격자가 개인키로 g^ab를 복원하면, 지난 1년간 저장해둔 트래픽을 전부 복호화할 수 있습니다.

PFS 있으면: Phase 2마다 새로운 DH 교환을 수행합니다. 1시간마다 SA를 갱신할 때 새로운 공유 비밀을 만들고, 이전 공유 비밀은 폐기합니다. 공격자가 현재 개인키를 탈취해도, 과거의 공유 비밀은 이미 사라졌으므로 복원할 수 없습니다. 저장해둔 과거 트래픽은 복호화할 수 없습니다.


트래픽 선택기: 어떤 트래픽을 터널로 보낼까

마지막으로, 어떤 트래픽을 이 터널로 보낼지 정의합니다. 앞서 SPD에서 “10.1.0.0/16 → 10.2.0.0/16은 PROTECT” 정책을 봤습니다. 트래픽 선택기가 이 정책의 조건을 정의합니다.

1
2
3
4
5
6
7
트래픽 선택기:
┌───────────────────────────────────────────────┐
│ 로컬: 10.1.0.0/16 (서울 본사 내부 네트워크)  │
│ 원격: 10.2.0.0/16 (부산 지사 내부 네트워크)  │
└───────────────────────────────────────────────┘

이 조건에 맞는 트래픽 → SPD에서 PROTECT → 서울→부산 SA로 암호화

서울(10.1.0.0/16)과 부산(10.2.0.0/16) 간의 트래픽만 터널을 통과합니다. 서울에서 Google(8.8.8.8)로 가는 트래픽은 SPD에서 BYPASS 정책에 매칭되어 터널을 거치지 않고 인터넷으로 직접 나갑니다.


IPsec의 장단점

왜 IPsec이 수십 년간 표준인가

IPsec을 대체하려는 기술들이 계속 등장하지만, 기업 환경에서 IPsec은 여전히 첫 번째 선택지입니다.

벤더 호환성. 시스코, 주니퍼, 포티넷, AWS, Azure, GCP 등 사실상 모든 네트워크 인프라가 IPsec을 지원합니다. 서울 본사가 시스코를 쓰고 부산 지사가 주니퍼를 써도 IPsec으로 연결할 수 있습니다.

검증된 보안. 1990년대부터 사용되어 온 알고리즘들입니다. 30년간 수많은 보안 연구자들이 분석했고, 취약점이 발견되면 빠르게 패치되었습니다.

투명한 동작. IP 계층에서 동작하므로, 상위 애플리케이션은 VPN의 존재를 모릅니다. 서울 본사의 10.1.0.5에서 부산 지사의 10.2.0.5로 접속할 때, 애플리케이션은 그냥 10.2.0.5로 연결할 뿐입니다. 중간에 IPsec 터널이 있다는 것을 알 필요가 없습니다.

하드웨어 가속. 대부분의 기업용 방화벽에는 AES 암호화 전용 칩이 있습니다. 소프트웨어로 암호화하면 CPU 부하가 크지만, 하드웨어 가속을 쓰면 수십 Gbps의 트래픽도 처리할 수 있습니다.


그런데 왜 복잡하다고 하는가

IPsec의 강점인 “풍부한 옵션”이 양날의 검입니다.

파라미터 불일치. IKE 버전(v1/v2), DH 그룹, 암호화 알고리즘, 무결성 알고리즘, 수명 등 수십 개의 파라미터가 양쪽에서 정확히 일치해야 합니다. 서울 본사에서 DH Group 14를 설정하고 부산 지사에서 Group 19를 설정하면 IKE_SA_INIT 단계에서 협상이 실패합니다. 로그가 불친절한 장비에서는 어느 파라미터가 불일치하는지 찾기 어렵습니다.

NAT 환경 설정. IKEv2는 NAT를 자동 감지하지만, 방화벽 설정은 수동으로 해야 합니다. UDP 500(IKE), UDP 4500(NAT-T), 그리고 NAT-T를 사용하지 않는 경우 ESP(프로토콜 50)를 모두 허용해야 합니다.

모바일 환경의 한계. 스마트폰으로 VPN을 연결한 상태에서 Wi-Fi에서 LTE로 전환하면 IP 주소가 바뀝니다. SA는 특정 IP 주소 쌍에 바인딩되어 있으므로, IP가 바뀌면 SAD에서 SA를 찾을 수 없습니다. IKE 재협상이 필요하고, 그 사이 연결이 끊깁니다.


마무리

이 글에서 살펴본 내용을 정리하면:

  • IKE는 DH 알고리즘으로 공유 비밀을 생성하고, KDF로 암호화 키와 인증 키를 파생합니다.
  • SA는 협상 결과(알고리즘, 키, 수명)를 저장합니다. 단방향이므로 서울→부산, 부산→서울 각각의 SA가 필요합니다.
  • SAD는 활성화된 SA들을 저장하고, SPD는 어떤 트래픽에 어떤 SA를 적용할지 정책을 정의합니다.
  • ESP는 암호화 키로 데이터를 암호화하고, 인증 키로 ICV를 계산하여 무결성을 검증합니다. SPI로 SA를 식별하고, 시퀀스 번호로 재전송 공격을 막습니다.
  • Tunnel Mode는 원본 패킷 전체를 암호화하여 내부 IP 주소를 숨깁니다.
  • NAT-T는 ESP 패킷을 UDP로 감싸서 NAT 환경에서도 동작하게 합니다.


IPsec은 복잡합니다. 하지만 30년간 검증된 보안과 벤더 호환성 덕분에 기업 VPN의 표준으로 자리잡았습니다.

Part 3에서는 IPsec의 복잡함을 줄이려는 현대 VPN 기술들을 살펴봅니다.


관련 글

시리즈

Tags: ESP, IKE, IPsec, VPN, 네트워크, 암호화

Categories: ,