요약

  • RFC 1701은 GRE에 선택적 4옥텟 Key 필드를 두고 이것이 패킷 출처를 인증하는 데 쓰일 수 있다고 언급했지만, 그 주장을 생성하거나 배포하거나 보호하거나 검증하는 방법은 정의하지 않았습니다.
  • RFC 2890은 나중에 이 경계를 명확히 했습니다. Key는 터널 안의 하나의 논리적 트래픽 흐름을 식별하며, "이름과는 달리" 어떤 보안 역할도 수행하지 않습니다. Sequence Number는 그 흐름의 순서를 정할 수 있지만 전달은 여전히 비신뢰적입니다.
  • 임의의 Sequence 값을 주입할 수 있는 공격자는 수신기 상태를 앞으로 밀어 정상 패킷이 낡은 것처럼 보이게 만들 수 있습니다. 별도의 보호 계층이 GRE 헤더와 페이로드를 덮어줄 때에만 분류와 순서 판단이 신뢰할 수 있게 됩니다.

그 권위가 알려지기 전에 이름을 얻은 필드

키라는 단어는 기대를 불러일으킵니다. 일상 언어에서 키는 무언가를 엽니다. 암호학에서는 보호된 변환을 선택하거나 활성화합니다. 접근 제어에서는 자격 증명을 뜻하기도 합니다. 따라서 그 이름을 달고 나타나는 패킷 필드는 프로토콜이 그 자격을 입증하기도 전에 운영자의 마음속에서 권위를 얻을 수 있습니다.

GRE의 역사는 이 위험을 이례적으로 선명하게 기록하고 있습니다. 1994년 10월 정보성(Informational) 문서로 발표된 RFC 1701은 하나의 네트워크 계층 프로토콜을 다른 프로토콜 위에 실어 나르는 일반적인 방법을 제안했습니다. 전달 헤더가 GRE 헤더를 감싸고, GRE 헤더는 다시 페이로드를 기술했습니다. 이 헤더는 체크섬, 라우팅 정보, 4옥텟 Key, 4옥텟 Sequence Number를 담을 수 있었습니다.

Key에 대해 그 문서는 수신기가 이 값을 패킷 출처를 인증하는 데 사용할 수 있다고 말했습니다. 진위를 판단하는 기법은 명세의 범위 밖이었습니다. 값을 생성하는 알고리즘도 없었습니다. 값을 엔드포인트에 묶는 교환도 없었습니다. 재사용을 막는 신선도 규칙도 없었습니다. 중간자가 값을 바꾸지 못하게 하는 무결성 메커니즘도 없었습니다. 추측된 값과 유출된 값을 구분하는 실패 절차도 없었습니다.

그 문장은 언제든 켤 수 있는 인증 프로토콜이 아니었습니다. 채워지지 않은 인터페이스였습니다. 두 구현체가 서로 호환되지 않는 증거적 무게를 부여한 채 동일한 4바이트를 회선에 올릴 수 있었습니다.

Sequence Number도 같은 미완성의 형태였습니다. RFC 1701은 수신기가 부호 없는 32비트 값을 전송 순서 확립에 사용할 수 있다고 말한 뒤, 생성과 수신 의미 모두를 문서 밖에 남겨두었습니다. 이 필드에는 자리는 있었지만 아직 상호운용 가능한 상태 기계는 없었습니다.

기본 명세는 의도적으로 더 작아졌다

RFC 2784는 2000년 3월에 다른 접근을 택했습니다. 여러 벤더가 이미 배포한 GRE 동작의 교집합을 기술하고, 그 작은 공통 형태를 표준 트랙에 올렸습니다. 기본 헤더는 Checksum-present 비트, Version, Protocol Type을 유지했습니다. Protocol Type은 캡슐 해제기에 뒤따르는 페이로드의 종류를 알려줍니다. 이전의 Key, Sequence, Routing 자리는 조용히 재해석되지 않았습니다.

대신 비트 1부터 5까지는 호환성 경계로 다뤄졌습니다. 수신기는 RFC 1701을 구현하지 않는 한 이 비트 중 하나라도 설정된 패킷을 폐기해야 했습니다. RFC 2784만 따르는 송신기는 예약된 자리를 0으로 보냈습니다. 별도의 상호운용성 절에서 구형 송수신기가 새 기본 명세와 어떻게 만날 수 있는지 설명했습니다.

이것은 지움(消去)이 아니라 절제였습니다. 공통 헤더에는 벤더 간 동작 코드가 이미 공유할 수 있는 것만 들어갔습니다. 새로운 계약 없는 선택적 의미는 그 호환성 집합의 바깥에 시각적으로 남았습니다. 파서는 벤더 이름, 터널 주소, 운영자의 의도를 근거로 추측하지 않았습니다.

이 설계는 GRE의 권위도 좁게 유지했습니다. 프로토콜은 캡슐화와 캡슐 해제를 규정했습니다. 패킷이 언제 터널에 들어가야 하는지는 정하지 않았습니다. 그 입장 결정은 구성과 주변 제어 시스템에 속했습니다.

RFC 2890은 Key를 덜 거창하게 만들어 유용하게 만들었다

6개월 뒤 RFC 2890이 기본 명세를 갱신했습니다. RFC 1701의 비트 자리를 재사용했습니다. K는 4옥텟 Key를, S는 4옥텟 Sequence Number를 표시합니다. 이 확장은 이전 배치와 회선 호환되지만 더 이상 필드의 핵심 임무를 상상에 맡기지 않았습니다.

캡슐화기가 Key를 삽입합니다. 그 값을 어떻게 얻는지는 RFC의 범위 밖입니다. 캡슐 해제기는 그 값으로 터널 안의 개별 트래픽 흐름을 식별하며, 특히 캡슐화된 데이터에 라우팅이나 처리에 필요한 맥락이 없을 때 유용합니다. 하나의 흐름에 속한 패킷들은 같은 값을 담습니다. 이 필드는 두 터널 엔드포인트 사이의 논리적 관계를 만듭니다.

이 관계가 유용한 것은 정확히 국소적이기 때문입니다. 하나의 외부 터널이 수신 엔드포인트가 서로 다른 맥락으로 보내야 하는 트래픽을 실을 수 있습니다. 모든 페이로드에 제어 평면 설명 전체를 복사하는 것보다 작은 숫자가 저렴합니다. 수신기는 수신한 값과 터널 맥락을 자신의 흐름 상태로 대응시키는 결정론적 매핑만 있으면 됩니다.

그 이상은 증명하지 못합니다. 패킷을 삽입하거나 변조할 수 있는 사람이라면 누구나 4바이트 숫자를 복제할 수 있습니다. 이 값은 비밀이 아니고, 서명을 담지 않으며, 송신자가 그 흐름을 선택할 자격이 무엇이었는지 말해주지 않습니다. RFC 2890은 Security Considerations에서 이 모호함을 닫습니다. Key 필드는 그 이름에도 불구하고 어떤 종류의 보안에도 관여하지 않습니다.

이 교정은 필드 이름을 바꾸지 않았습니다. 더 강력한 운영상 조치를 취했습니다. 필드의 주장을 고정한 것입니다. Key는 맥락을 선택할 수 있되 자격 증명으로 가장하는 것은 허용되지 않습니다.

Sequence는 순서를 주었을 뿐 전달은 주지 않았다

S 확장은 실행 가능한 수신 이력을 추가했습니다. 캡슐화기는 0부터 2^32−1까지 자유주행하는 카운터를 보내고 2^32를 법으로 나머지 연산으로 감습니다. 수신기는 성공적으로 캡슐 해제한 마지막 패킷의 번호를 기억합니다. K가 있으면 그 상태는 Key가 식별하는 논리적 흐름에 고유합니다.

정확히 한 단계 앞선 패킷은 순서에 맞습니다. 충분히 오래되었거나 중복된 값은 순서 밖이며 조용히 폐기해야 합니다. 앞서되 간격을 남기는 값은 누락되었거나 재정렬된 트래픽을 드러냅니다. 수신기는 그런 패킷을 흐름별 버퍼에 소수만큼 보관하고 잠시 간격을 기다렸다가 가진 것을 순서대로 내보낼 수 있습니다. 대기나 버퍼 한도가 끝나면 누락된 번호를 건너뛰고 진행할 수 있습니다.

문서는 결과를 신중하게 이름 짓습니다. 비신뢰적이지만 순서가 보장되는 전달(unreliable but in-order delivery)입니다. Sequence는 누락된 페이로드를 재전송하지 않습니다. 네트워크가 모든 데이터그램을 전달하리라고 약속할 수도 없습니다. 유한한 버퍼링은 이전 패킷이 아직 오고 있을지 모르는 동안 캡슐 해제기가 새 패킷을 얼마나 지연할지만 결정합니다.

S는 터널 전체에 하나의 총 순서를 부과하지도 않습니다. Sequence Number 없는 패킷은 그것을 담는 패킷과 끼어들 수 있습니다. K가 있으면 서로 다른 Key가 서로 다른 순서 이력을 유지합니다. 따라서 "더 새로운"이란 선택된 수신 맥락 안에서 더 새로운 것이지, 링크에서 관측된 모든 GRE 패킷보다 보편적으로 새로운 것은 아닙니다.

이 구분은 증거의 문제에서 중요합니다. 간격은 수신기가 그 흐름 상태에서 앞선 번호를 모두 성공적으로 캡슐 해제하지 못했다는 사실을 증명합니다. 그것만으로 패킷이 유실되었는지, 버퍼를 넘어 재정렬되었는지, 필터링되었는지, 위조되었는지, 터널과 함께 재설정되었는지, 애초에 전송되지 않았는지는 알려주지 않습니다.

위조된 미래는 정당한 현재를 지울 수 있다

보안 실패는 그밖에는 유용한 상태 기계에서 직접 따라옵니다. 수신기가 마지막으로 Sequence 40을 받았다고 합시다. 올바른 터널 주소, 복제된 Key, 훨씬 뒤의 Sequence 값을 담은 악의적 패킷이 캡슐 해제기에 먼저 도착합니다. 헤더를 인증하는 외부 메커니즘이 없다면 수신기는 자신의 기억을 주입된 미래로 밀어버릴 수 있습니다. 뒤따르는 정상 패킷들은 이제 낡은 것으로 보여 폐기됩니다.

RFC 2890은 임의의 Sequence 주입을 서비스 거부 경로로 명시합니다. 그 처방은 더 인상적인 Key 값도 더 큰 카운터도 아닙니다. GRE 헤더와 터널링된 페이로드에 대한 IP 보안 보호를 요구합니다. 결정적인 성질은 커버리지입니다. 출처와 무결성이 수신기 상태를 움직이는 바로 그 필드들을 포함해야 합니다.

그래서 Sequence Number는 안티 리플레이 보호가 아닙니다. 안티 리플레이 윈도우는 패킷이 보호된 연관에 속하는 것으로 인증된 다음에만 의미가 있습니다. 그 선행 검사가 없으면 공격자가 이후 패킷들이 판정받을 근거 자체를 써넣을 수 있습니다.

암호화도 별개의 문제입니다. 보호된 터널은 페이로드를 감추지 않고 인증할 수도 있고, 주변 메커니즘과 정책에 따라 두 성질을 모두 제공할 수도 있습니다. GRE의 K와 S 비트는 어느 쪽도 선택하지 않습니다. 흐름 조회가 성공했다고 해서 기밀성에 대해 아무것도 말해주지 않습니다.

이후의 의무들은 Key를 부풀리지 않았다

GRE 기본 명세는 진화를 멈추지 않았습니다. 2024년에 발표된 RFC 9601은 RFC 2784의 또 다른 갱신으로 기록되어 있습니다. IP 헤더 사이에서 쓰이는 GRE를 Explicit Congestion Notification 전파의 현대적 규칙 안에 놓고, 외부 전달 프로토콜이 IPv4 또는 IPv6일 때 안전한 인그레스 구성 요건을 추가합니다.

이 갱신은 RFC 2890과 직교합니다. ECN은 혼잡 증거가 안쪽과 바깥쪽 IP 헤더를 가로질러 어떻게 넘어가는지 묻습니다. Key는 엔드포인트가 어떤 논리적 흐름 맥락을 선택하는지 묻습니다. Sequence는 수신기가 해당 흐름 안에서 패킷을 어떻게 정렬하는지 묻습니다. 보호는 헤더와 페이로드가 변경 없이 수용된 보안 연관에서 왔는지 묻습니다. 하나의 터널이 이 네 가지 책임을 모두 수행할 수 있지만, 어느 필드도 다른 필드의 권위를 물려받지 않습니다.

RFC 9601은 GRE 자체에는 동적 터널 설정 메커니즘이 없다는 점도 짚습니다. 다른 제어 평면 프로토콜이나 정적 구성이 그 관계를 만들 수 있습니다. 패킷 캡처는 회선 위의 K와 S를 보여줄 수 있습니다. 그것만으로 Key를 할당한 합의나 피어를 승인한 근거를 복원할 수는 없습니다.

솔직한 운영 질문

운영자는 "GRE 키가 일치하는가?"만 물어서는 안 됩니다. 유용한 질문은 계층화되어 있습니다. 어느 외부 엔드포인트와 구성된 터널이 이 네임스페이스를 공급했는가? 그 숫자가 어느 로컬 흐름을 선택하는가? 이 패킷에 K가 있을 것으로 예상되었는가? 이 흐름에 S가 요구되는가? 마지막으로 받은 값은 무엇이었고, 어떤 간격이나 순환(wrap)이 있었으며, 헤더가 인증된 무결성 경계 안에 있었는가?

카운터에도 같은 규율이 필요합니다. 순서 밖 폐기의 증가는 재정렬, 중복, 버퍼 압박, 상태 재설정, 불일치하는 엔드포인트 구성, 또는 적대적 주입을 반영할 수 있습니다. 카운터는 수신기의 결정을 기록합니다. 그것은 자신의 원인을 담고 있지 않습니다.

따라서 RFC 2890의 역사적 성취는 GRE가 더 강해 보이는 필드를 얻었다는 것이 아니었습니다. 동작 중인 엔드포인트가 더 작고 검증 가능한 주장을 얻었다는 것입니다. Key는 맥락의 이름이 될 수 있었습니다. Sequence Number는 그 맥락이 받은 것의 순서를 정할 수 있었습니다. 보안은 그 증거가 둘 모두를 감싸야 하는 별개의 의무로 남았습니다.

출처