엔티티 인증 없는 키 교환 (Insecure Host Key Verification)

Key Exchange without Entity Authentication

설명

이 취약점은 SSH 클라이언트가 서버의 host key(서버 공개키)를 검증하지 않고 그냥 신뢰할 때 발생합니다. Go에서 ssh.InsecureIgnoreHostKey() 를 사용하면, 클라이언트는 접속하는 서버가 진짜 서버인지 확인하지 않게 됩니다. 공격자는 네트워크 중간에서 위조된 SSH 서버를 띄우고 사용자의 트래픽을 가로채는 Man-in-the-Middle(MitM) 공격을 할 수 있습니다. 사용자는 정상 서버에 접속한다고 생각하지만, 실제로는 공격자 서버에 접속하게 되고, 자격 증명(계정/비밀번호, private key 사용 세션)과 전송되는 중요 데이터를 탈취할 수 있습니다.

잠재적 영향

  • 중간자 공격(MitM, Man-in-the-Middle): 서버의 진위를 확인하지 않아 공격자가 가짜 SSH 서버로 트래픽을 가로채서 세션 내용을 엿보거나 변조할 수 있음

  • 자격 증명 탈취: SSH 비밀번호, 토큰, 명령 실행 결과 등의 민감 정보가 공격자에게 노출될 수 있음

  • 원격 명령 조작: 공격자가 클라이언트와 서버 사이의 명령 또는 응답을 바꿔, 의도치 않은 명령을 실행시키거나 잘못된 데이터를 보내도록 만들 수 있음

해결 방법

  • ssh.InsecureIgnoreHostKey() 사용 금지: 절대 프로덕션 코드에서 사용하지 않습니다.

  • known_hosts 기반 검증 사용: golang.org/x/crypto/ssh/knownhosts 패키지의 knownhosts.New 를 사용해 OpenSSH 형식의 known_hosts 파일로 서버 host key를 검증합니다.

  • 고정된(host pinned) 공개키 사용: 제한된 환경에서는 ssh.FixedHostKey() 로 미리 신뢰한 서버 공개키만 허용하는 방식으로 검증합니다.

  • 키 관리 정책 수립: known_hosts 파일 또는 pinned key를 안전하게 배포·관리하고, 서버 키가 변경될 경우 운영 절차에 따라 안전하게 업데이트합니다.

  • 개발·테스트 환경에서도 검증 습관화: 테스트 편의를 이유로 InsecureIgnoreHostKey를 남겨두지 말고, 테스트용 known_hosts 또는 테스트용 고정 키를 사용합니다.

취약한 코드 및 안전한 코드 예시

취약한 코드

안전한 코드

설명:

  • 취약한 코드: HostKeyCallback: ssh.InsecureIgnoreHostKey() 설정은 SSH 서버의 host key를 전혀 검증하지 않습니다. 따라서 공격자가 네트워크 중간에 가짜 SSH 서버를 띄워도 클라이언트는 이를 정상 서버로 믿고 접속합니다. 이 과정에서 비밀번호, 명령, 결과 값 등 민감 정보가 모두 공격자에게 노출될 수 있고, 세션이 완전히 장악될 수 있습니다.

  • 안전한 코드: knownhosts.New 를 이용해 OpenSSH 형식의 known_hosts 파일을 읽고, HostKeyCallback 으로 설정함으로써 서버 host key가 신뢰된 값인지 자동 검증합니다. 서버 키가 다를 경우 SSH 연결이 실패하므로, 중간자 공격이나 가짜 서버에 대한 접속이 차단됩니다. 이렇게 서버의 엔티티(정체)를 인증함으로써 키 교환과 통신 채널의 기밀성과 무결성을 보호할 수 있습니다.

참조

Last updated