같은 SSTP 배포를 두고 두 사람이 정반대 결론에 이를 수 있다. 한 사람은 제품 문서를 읽고 SSL이라는 글자를 보고서는 몇 년 전에 폐기된 프로토콜이 터널에서 돌고 있다고 가정한다. 다른 사람은 현대적인 핸드셰이크를 가리키며 질문은 끝났다고 말한다. 둘 다 협상된 버전이 아니라 라벨로 논쟁하며, 증거가 되는 것은 둘 중 하나뿐이다. 할 만한 비교는 이름이 약속하는 것과 서비스가 실제로 고르는 것 사이에 있다.

같은 질문에 대한 두 가지 답

라벨 논증은 말하기 쉽다. SSTP는 안전한 소켓 터널링 프로토콜로 설명되고, 역사적 이름에는 SSL이 들어 있으니 연결은 SSL 3.0이어야 한다. 이것이 살아남는 이유는 이름이 정말 그 계보에서 왔기 때문이고, 되풀이하는 사람 대부분이 핸드셰이크를 한 번도 본 적이 없기 때문이다. 결론이 신중하게 들리기 때문이기도 하다. 최악을 가정하는 것이 안전한 선택이라는 식이다. 최악을 가정하는 것과 실제 버전을 재는 것은 다른 행위이며, 무엇인가를 바꾸는 것은 한쪽뿐이다.

증거 논증은 더 좁은 질문을 던진다. 이 클라이언트와 이 서버가 이 엔드포인트에서, 이 시점에 어떤 프로토콜 버전에 합의했는가. 답은 TLS를 종료하는 서비스에서 나오며, 마케팅 페이지나 비슷한 이름의 사이트에 도달한 브라우저에서 나오지 않는다.

두 논증은 증명할 수 있는 것이 다르다. 라벨은 오래된 배포와 패치된 배포를 구별하지 못하고, 핸드셰이크는 같은 호스트의 무관한 서비스가 무엇을 하는지 알려주지 않는다. 후자를 쓰고 전자는 쓰지 말아야 한다.

서비스가 실제로 고르는 버전을 읽어라

먼저 구성 요소를 지목한다. 클라이언트 구현, 서버 구현, TLS 엔드포인트, 그리고 그 사이에서 TLS를 종료하고 다시 세우는 모든 것. TLS를 종료하고 백엔드와 평문 HTTP로 대화하는 로드 밸런서가 있으면 어느 장비의 정책을 읽어야 하는지가 달라진다.

openssl s_client -connect vpn.example.com:443 -servername vpn.example.com </dev/null> | grep -E 'Protocol|Cipher'
Get-WinEvent -LogName System -ProviderName Schannel -MaxEvents 20

결과 옆에 엔드포인트와 시각을 기록한다. 나중에 정책이 바뀌면 날짜 없는 관찰은 쓸모없어지기 때문이다. 관심 있는 사용자와 같은 네트워크 경로에 있는 클라이언트에서 다시 시험한다. 중간의 차단 장비가 자체 설정으로 TLS를 종료할 수 있기 때문이다. 두 위치의 결론이 어긋나면 중요한 구성 요소를 찾은 것이다. 일치하면 구호가 아니라 증거를 가진 것이다.

레코드 필드와 협상을 분리하라

한 필드의 낡아 보이는 버전 번호는 SSL 3.0 세션과 같은 사실이 아니다. RFC 7568은 레코드 계층 버전과 협상된 프로토콜을 별개의 문제로 다루며, 자신감 있는 오답은 바로 이 구분에서 나온다. 협상된 프로토콜을 읽고, 그다음 암호 스위트를 읽고, 그다음에야 세션에 대해 결론을 내려야 한다.

같은 문서는 프로토콜 자체에 대해 분명하다. SSL 3.0은 사용해서는 안 되고, 그것으로의 협상이나 폴백은 금지된다. 이유는 POODLE 공격이 악용한 깨진 CBC 구조이며, 이는 프로토콜의 성질이지 한 애플리케이션의 설정이 아니다.

그래서 “이 워크로드는 악용하기 어려울 것”은 SSL 3.0을 켜 둘 이유가 되지 않는다. 요구는 프로토콜을 제거하는 것이지, 한 번의 시연에 대한 논쟁에서 이기는 것이 아니다.

설명 가능한 정책으로 SSL 3.0을 퇴역시켜라

Windows에서는 Schannel 프로토콜 설정이 Protocols 키 아래에 있고 클라이언트 역할과 서버 역할에 대해 따로 읽힌다. 그래서 한 방향을 고치는 변경이 다른 방향을 그대로 둘 수 있다. 현재 설정과 재시작 요구 사항은 Microsoft가 문서화했으며, 같은 호스트의 서드파티 TLS 라이브러리는 이를 전혀 무시한다.

Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server'
Get-ChildItem 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols'

지원되는 관리 경로로 정책을 바꾸고, 소유 서비스가 구성을 다시 읽는지 확인하고, 승인된 되돌림 경로를 남긴다. 다른 환경의 광범위한 레지스트리 스크립트를 붙여넣는 것은 한 서비스의 수정이 머신의 모든 TLS 클라이언트 중단으로 번지는 방식이다. 재시작 범위가 여기서 중요하다. 적용된 것처럼 보이는 설정이 다시 읽지 않은 서비스의 메모리에 남아 있을 수 있다.

아직 구버전을 요구하는 상대는 업데이트나 이전 계획이 필요하다. 문서화되지 않은 예외로 옛 프로토콜을 조용히 되살리는 것은 호환성 전략이 아니며 다음 감사도 버티지 못한다.

새 연결로 변경을 받아들여라

정책 변경 후에는 새 세션으로 시험한다. 변경 전에 맺은 연결은 지금 유효한 구성에 대해 아무것도 증명하지 않기 때문이다. 허용된 프로토콜이 성공하고 금지된 프로토콜이 승인된 검증 절차에서 실패하는지 확인하고, 인증서 신원과 신뢰 확인은 그대로 둔다.

핸드셰이크가 덮지 않는 것을 잊지 말아야 한다. SSTP는 TLS 계층 뒤에 PPP 인증을 실어 나르므로, 현대적인 프로토콜 버전은 누가 인증되었는지, 세션이 어떤 자원에 닿을 수 있는지에 대해 아무것도 말하지 않는다. 그것은 별도의 통제이며 별도의 증거가 필요하다.

결과를 서비스, 백엔드, 허용된 정책, 관찰된 버전으로 적는다. 그러한 기록만이 보안 질문에 정확히 답한다. 라벨 논증도, 번거롭다는 논증도 그렇게 하지 못한다.

관련 글