여기서 가장 큰 피해를 만드는 것은 두 가지 믿음입니다. 자체 서명 VPN 인증서가 터널이 암호화되지 않았다는 뜻이라는 믿음, 그리고 VPN 클라이언트가 요청한 무엇이든 설치하는 것이 VPN에만 영향을 준다는 믿음입니다. 둘 다 실제 배포를 만나면 버티지 못합니다. 자체 서명 인증서는 서명 관계를 설명할 뿐 보안 판결이 아닙니다. 추가한 신뢰의 범위는 그것이 어느 저장소에 들어가느냐에 달려 있습니다. 헬프데스크가 경고 하나를 잠재우려고 공급자 루트를 Windows 컴퓨터에 가져온 뒤, 브라우저가 무관한 포털에 대해 불평을 멈춘 이유를 반나절 동안 설명하는 것을 본 적이 있습니다. 이 질문의 두 절반은 함께 가야 하므로 하나로 다루십시오.

인증서는 신뢰 저장소가 아니다

서버가 제시하는 파일에는 공개 키, 주체 이름, 발급자 이름, 유효 기간, 확장이 들어 있습니다. 자체 서명은 주체와 발급자가 같은 실체이고 서명이 인증서 자체의 키로 검증된다는 뜻입니다. 그 정의 어디에도 연결이 약하다고 쓰여 있지 않고, 클라이언트가 받아들일 것이라고도 쓰여 있지 않습니다.

수용은 다른 곳에서 옵니다. 클라이언트를 가리키는 CA 파일, 손으로 비교하는 지문, 또는 클라이언트가 읽는 저장소에 이미 있는 루트입니다. 배포가 완전히 건전해도 그 인증서는 모든 공개 테스트에서 떨어질 수 있습니다. openssl verify 은 시스템 번들에 대해 알 수 없는 발급자를 보고하며, 그 보고는 결함이 아니라 정확합니다.

OpenVPN의 ca 옵션은 앱 범위 신뢰의 가장 분명한 사례입니다. 그 파일은 클라이언트가 받아들일 앵커를 지정하며, 하나의 사설 CA 또는 소규모 배포에서는 서버 자체의 자체 서명 인증서를 담을 수 있습니다. 버전 2.6은 CA 파일을 배포하는 대신 SHA-256 지문을 고정하기 위해 --peer-fingerprint 도 받아들입니다. WireGuard는 더 바깥에 있습니다. 인증서가 전혀 없고 피어마다 정적 공개 키만 있으므로 자체 서명 질문이 적용되지 않습니다.

신뢰를 어디에 설치하느냐가 누가 그것을 물려받는지를 결정한다

같은 인증서를 세 곳에 두면 세 가지 다른 폭발 반경을 얻습니다. VPN 클라이언트만 읽는 번들은 그 클라이언트에 영향을 줍니다. 운영 체제 저장소의 루트는 그 저장소를 참조하는 모든 프로그램에 영향을 줍니다. 자체 신뢰 데이터베이스를 가진 브라우저는 둘 다 무시할 수 있으며, 그래서 작동한 것처럼 보인 가져오기 후에도 경고가 남을 수 있습니다.

Debian이나 Ubuntu에서는 /usr/local/share/ca-certificates/ 에 파일을 넣고 update-ca-certificates 를 실행하면 시스템 전체 번들이 바뀝니다. Windows에서는 certutil -addstore -f Root 가 컴퓨터 저장소에 쓰고 상승된 프롬프트가 필요하며, -user 를 추가하면 대신 현재 사용자 저장소를 대상으로 합니다. 둘은 서로 바꿀 수 없습니다. Firefox는 자체 NSS 데이터베이스를 유지하므로 OS 수준 가져오기가 거기에 나타나지 않을 수 있습니다.

범위가 중요한 이유는 권한이 무엇을 할 수 있는지 때문입니다. 발급 CA는 관계없는 이름에도 서명할 수 있으므로 그 저장소를 신뢰하는 모든 것은 그 서명을 받아들입니다. 고정된 리프 하나는 그렇게 할 수 없습니다. 정확히 하나의 피어 신원을 인증합니다. 목표가 VPN 하나를 연결하는 것이라면 앱 범위 CA나 고정된 리프로 도달하며, 컴퓨터 전체 루트는 증상이 요구하는 것보다 훨씬 큰 양보입니다.

공개 CA 없이도 여전히 암호화하고 있다

TLS 핸드셰이크는 피어 인증서가 이미 신뢰하는 것에 연결되는지와 무관하게 세션 키를 도출합니다. 자체 서명은 평문을 뜻하지 않고, 트래픽이 비행 중에 읽힌다는 뜻도 아닙니다. 뜻하는 것은 클라이언트가 키가 요청한 서버의 것이라고 믿을 선험적 이유가 없다는 것입니다.

바로 그 틈에서 실제 공격이 삽니다. 어떤 인증서든 받아들이도록 구성된 클라이언트는 검증 설정을 껐거나 한 번 누르고 잊힌 ‘그래도 신뢰’ 버튼을 통해, 응답하는 누구에게나 기꺼이 암호화합니다. 가로채기는 인증 단계에서, 애플리케이션 데이터가 움직이기 전에 일어납니다. 신원 확인 없는 암호화는 수동적 관찰자를 밖에 두고 그 이상은 거의 하지 않습니다.

발급자를 신뢰해도 이름 검사를 건너뛰지 않는다

체인 검증, 이름 일치, 인증서 용도는 별개의 결정입니다. 체인이 유효해도 이름이 틀릴 수 있고, 이름이 일치해도 인증서가 다른 역할을 위해 발급되었을 수 있습니다. RFC 5280 은 그 제약을 담는 필드를 정의하며, 클라이언트가 얼마나 엄격히 적용하는지는 애플리케이션마다의 문제입니다.

OpenVPN은 그 분리를 보이게 합니다. verify-x509-name 은 name, name-prefix 또는 subject 일치를 통해 예상 주체를 고정합니다. remote-cert-tls server 은 피어 인증서가 서버 인증서로 쓰일 수 있기를 요구하며, 발급자가 신뢰되더라도 클라이언트 전용 인증서를 거부합니다. 두 설정 모두 CA 파일을 보내는 것으로 대체되지 않습니다.

무엇이든 결정하기 전에 인증서를 살펴보십시오:

  • openssl x509 -in server.crt -noout -subject -issuer -dates -ext subjectAltName 은 누가, 어느 이름을 위해, 언제까지 발급했는지 보여 줍니다.
  • openssl verify -CAfile ca.crt server.crt 은 보내려는 체인이 실제로 리프를 검증하는지 확인합니다.
  • openssl s_client -connect vpn.example.net:443 -servername vpn.example.net -CAfile ca.crt -verify_return_error 은 웹 포털 같은 TLS 엔드포인트에 작동합니다. 1194번의 OpenVPN 프로토콜은 일반 TLS 스트림이 아니므로 그 테스트는 거기에 적용되지 않습니다.

만료된 날짜, 연결하는 이름에 대한 subjectAltName 없음, 또는 serverAuth 용도 없음이 있는 인증서는 앵커가 아무리 주의 깊게 설치되었어도 실패합니다.

하나를 받아들이기 전 다섯 가지 검사

고치려는 연결이 아닌 채널로 지문을 비교하십시오. 콘솔, 이미 가지고 있는 설치 프로그램, 서명된 구성 파일입니다. 서버의 openssl x509 -in server.crt -noout -fingerprint -sha256 과 클라이언트 로그의 같은 값이면 하나의 객체를 보고 있다는 것을 알 수 있습니다.

다음으로 리프 하나인지, 더 찍어낼 수 있는 권한인지, 무엇을 설치하는지 결정하십시오. 그다음 그것이 어디로 가는지 정하고 그 저장소를 읽는 애플리케이션을 지목하십시오. 아직 기억할 때 제거 경로를 적어 두십시오. ‘신뢰하고 넘어가기’가 임시 가져오기를 영구적으로 만드는 길이기 때문입니다.

마지막으로 변경을 계획하십시오. 고정된 인증서나 지문은 인증서가 교체될 때 같은 신뢰 채널로 갱신해야 하며, 사설 CA는 자체 발급 및 폐기 수명 주기가 있습니다. 개인 키가 유출되면 같은 인증서 사본을 다시 신뢰해도 아무것도 고쳐지지 않습니다. 신원을 교체해야 합니다.

경고가 다섯 검사를 모두 통과한다면 유용한 질문은 어느 버튼이 그것을 잠재우느냐가 아니라 클라이언트가 실제로 어느 저장소를 읽고 그 루트가 어디서 왔느냐입니다. 그것에 답하면 하려는 가져오기는 반사가 아니라 결정이 됩니다.

관련 글