Missing SSH host key verification

ID

go.missing_ssh_host_key_verification

Severity

critical

Resource

Misconfiguration

Language

Go

Tags

CWE:322, NIST.SP.800-53, OWASP:2021:A1, OWASP:2021:A5, PCI-DSS:6.5.4

Description

The application establishes SSH connections without verifying the host key, which can expose it to man-in-the-middle (MITM) attacks.

Rationale

In Go, using the golang.org/x/crypto/ssh package, it is common to configure SSH clients with a HostKeyCallback. Skipping host key verification (for example, using ssh.InsecureIgnoreHostKey()) disables validation of the server’s identity. This allows attackers to intercept or tamper with SSH communications.

package main

import (
    "golang.org/x/crypto/ssh"
)

func main() {
    // Insecure: host key verification is skipped
    config := &ssh.ClientConfig{
        User: "user",
        Auth: []ssh.AuthMethod{
            ssh.Password("password"),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }

    client, err := ssh.Dial("tcp", "example.com:22", config)
    if err != nil {
        panic(err)
    }
    defer client.Close()
}

Using ssh.InsecureIgnoreHostKey() may seem convenient during development, but it removes all guarantees that the server being connected to is legitimate, creating a significant security risk.

Remediation

To remediate, always validate the server’s host key. This can be done by storing known host keys and using a proper HostKeyCallback function that checks the server key against the known list.

package main

import (
    "fmt"
    "io/ioutil"
    "golang.org/x/crypto/ssh"
)

func main() {
    // Load known_hosts file
    knownHosts, err := ioutil.ReadFile("/home/user/.ssh/known_hosts")
    if err != nil {
        panic(err)
    }

    hostKeyCallback, err := ssh.ParseKnownHosts(knownHosts)
    if err != nil {
        panic(err)
    }

    config := &ssh.ClientConfig{
        User: "user",
        Auth: []ssh.AuthMethod{
            ssh.Password("password"),
        },
        HostKeyCallback: hostKeyCallback,
    }

    client, err := ssh.Dial("tcp", "example.com:22", config)
    if err != nil {
        panic(err)
    }
    defer client.Close()

    fmt.Println("SSH connection established with verified host key")
}

Key points for remediation in Go: - Never use ssh.InsecureIgnoreHostKey() in production code. - Maintain a known_hosts file or an equivalent trusted store of host keys. - Implement a HostKeyCallback function that validates the server key against the trusted store.

References