요약

  • 원래의 TLS 재협상 설계는 기존 채널 안에 두 번째 핸드셰이크를 암호화해 넣었지만, 두 핸드셰이크를 암호학적으로 묶지는 않았습니다.
  • RFC 5746은 양쪽이 직전 Finished 메시지에서 온 증거를 제시하도록 함으로써 이 결함을 고쳤고, TLS 1.3은 이후 재협상 자체를 제거했습니다.

저자가 둘인 채널

공격은 안심이 되는 듯한 세부 사항에서 시작됩니다. 공격자는 서버에 유효한 TLS 연결을 엽니다. 그 연결에서 전송되는 모든 것은 암호화됩니다. 공격자는 그런 다음 애플리케이션 접두부를 전송합니다. HTTP 요청의 시작일 수도 있고, 이후 바이트가 의미를 완성할 명령일 수도 있습니다. 다음으로, 공격자는 교환을 홀로 끝내는 대신 피해자의 새 TLS 핸드셰이크를 이미 보호된 서버 측 연결 안으로 전달합니다.

피해자 입장에서는 실제 서버와의 최초 핸드셰이크입니다. 서버 입장에서는 공격자의 연결에 대한 재협상입니다. 새 핸드셰이크가 끝난 뒤 공격자는 피해자의 트래픽을 읽을 수 없습니다. 기밀성이 그저 사라진 것은 아닙니다. 실패한 것은 귀속입니다. 서버는 공격자의 접두부와 피해자의 인증된 바이트를 하나의 애플리케이션 스트림에 놓고 한 상대의 작업으로 취급할 수 있었습니다.

RFC 5746의 시퀀스 다이어그램은 이 취약점을 알기 쉽게 드러냈습니다. 전송 계층 연속성, 암호화 연속성, 애플리케이션 기록 연속성은 같은 성질이 아니었습니다. 안전한 터널이 암호학적 신원의 변경을 운반하면서도, 변경 전후의 바이트를 어떻게 이어 붙여야 하는지 증명하지 못할 수 있었습니다.

첫 핸드셰이크가 메모리에 남아 있어야 했던 이유

이 수정은 두 번째 핸드셰이크가 자신이 재협상이라고 선언만 하도록 요구하지 않았습니다. 그런 선언은 공격자가 복제할 수 있습니다. 수정은 양쪽 종단이 직전 핸드셰이크에서 연결별 증거, 즉 Finished 메시지의 클라이언트·서버verify_data값을 보관하도록 요구했습니다.

RFC 5746은renegotiation_info확장, 유형0xff01을 정의했습니다. 최초 핸드셰이크에서는 이 바인딩 필드가 비어 있는데, 이는 이전 핸드셰이크가 존재한다고 가장하지 않으면서도 양측이 안전한 재협상을 이해한다는 점을 확립하게 해 줍니다. 재협상하는 ClientHello에서는 이 필드가 저장된 클라이언트verify_data를 담고, 응답하는 ServerHello에서는 저장된 클라이언트·서버 값을 함께 담습니다. 값이 없거나 일치하지 않으면 사후에 기록할 경고가 아니라 핸드셰이크를 중단해야 합니다.

이 설계는 이전 핸드셰이크를 다음 핸드셰이크의 인증된 입력으로 만들었습니다. 이제 서버는 진짜 연속과, 다른 사람의 연결에 이식된 피해자의 최초 핸드셰이크를 구분할 수 있었습니다. 두 번째 핸드셰이크가 선행자를 기억해야 했던 이유는, 주변 소켓만으로는 증거가 되지 않았기 때문입니다.

배포된 프로토콜을 고치는 대가

이 전환은 모든 구형 구현이 ClientHello 확장을 올바르게 처리한다고 가정할 수 없었습니다. TLS 1.0 시절 소프트웨어 일부는 명세가 알 수 없는 확장은 무시하도록 요구했음에도, 이해하지 못한 확장을 만나면 실패했습니다. 그래서 RFC 5746은 실제 암호 스위트가 아니며 협상될 수 없는 시그널링 암호 스위트 값인TLS_EMPTY_RENEGOTIATION_INFO_SCSV를 만들었습니다. 이는 빈 최초 바인딩의 의미를 구형 서버가 더 받아들이기 쉬운 형태로 전달했습니다.

호환성이 모호함을 지우지는 않았습니다. 확장을 인정하지 않는 서버는 취약할 수도 있고, 새 신호 없이 모든 재협상을 안전하게 거부하는 중일 수도 있었습니다. TLS 자체만으로는 클라이언트가 두 경우를 구분할 수 없었습니다. 그래서 표준 문서는 최대 상호운용성과 이식(splice) 방지 보장 사이의 불편한 선택을 기록했습니다. 수정은 암호학적이었지만, 그 배포는 근거의 부재가 언제 연결을 끝내야 하는지를 결정하는 작업이었습니다.

제거라는 이후 형태의 안전

TLS 1.3은 더 좁은 상태 기계를 선택했습니다. RFC 8446은 재협상을 금지하며, 잘못된 시점에 도착한 ClientHello는 연결을 종료합니다. 재협상에 묶여 있던 기능은 분리되었습니다. 키 갱신과 핸드셰이크 후 인증은 별도의 규칙을 가진 별도 메커니즘으로 존재하며, 같은 자리에서 다른 핸드셰이크를 실행하던 옛 범용 능력을 되살리지 않습니다.

RFC 9325의 현재 지침은 이 역사적 경계를 유지합니다. TLS 1.2 클라이언트와 서버는renegotiation_info를 구현해야 하고, 클라이언트는 TLS 1.2 서버가 이를 인정하지 않으면 연결을 끊어야 합니다. TLS 1.3에서는 보호할 재협상이 없습니다. 교훈은 모든 전환이 금지되어야 한다는 것이 아닙니다. 인증이나 키를 바꾸는 전환은 자신이 어떤 이전 상태를 물려받는지 정확히 정의하고, 그 상속에 대한 암호학적 증거를 실어야 한다는 것입니다.

이 RFC들은 2009년 기법이 실제로 얼마나 이용되었는지 확립하지 않으며, 오늘 남아 있는 재협상 배포 수를 세지도 않습니다. 다만 프로토콜의 실패, 수정, 이후의 제거는 확립합니다. 이것만으로도 오래 지속되는 설계 규칙을 확인하기에 충분합니다. 암호화는 채널 안의 바이트를 보호할 뿐, 채널의 모든 단계가 같은 저자를 가진다는 것을 그 자체로 증명하지는 않습니다.

출처