sftp: Allow user to optionally check server hosts key to add security

Based on Issue 4087
  https://github.com/rclone/rclone/issues/4087

Current behaviour is insecure.  If the user specifies this value then we
switch to validating the server hostkey and so can detect server changes
or MITM-type attacks.
This commit is contained in:
Stephen Harris 2020-10-03 21:03:19 -04:00 committed by Nick Craig-Wood
parent 66def93373
commit 6dc28ef50a
2 changed files with 89 additions and 0 deletions

View file

@ -32,6 +32,7 @@ import (
"github.com/rclone/rclone/lib/readers"
sshagent "github.com/xanzy/ssh-agent"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/knownhosts"
)
const (
@ -86,6 +87,16 @@ in the new OpenSSH format can't be used.`,
Help: `Optional path to public key file.
Set this if you have a signed certificate you want to use for authentication.` + env.ShellExpandHelp,
}, {
Name: "known_hosts_file",
Help: `Optional path to known_hosts file.
Set this value to enable server host key validation.` + env.ShellExpandHelp,
Advanced: true,
Examples: []fs.OptionExample{{
Value: "~/.ssh/known_hosts",
Help: "Use OpenSSH's known_hosts file",
}},
}, {
Name: "key_use_agent",
Help: `When set forces the usage of the ssh-agent.
@ -195,6 +206,7 @@ type Options struct {
KeyFile string `config:"key_file"`
KeyFilePass string `config:"key_file_pass"`
PubKeyFile string `config:"pubkey_file"`
KnownHostsFile string `config:"known_hosts_file"`
KeyUseAgent bool `config:"key_use_agent"`
UseInsecureCipher bool `config:"use_insecure_cipher"`
DisableHashCheck bool `config:"disable_hashcheck"`
@ -414,6 +426,7 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
if opt.Port == "" {
opt.Port = "22"
}
sshConfig := &ssh.ClientConfig{
User: opt.User,
Auth: []ssh.AuthMethod{},
@ -422,6 +435,14 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
ClientVersion: "SSH-2.0-" + fs.Config.UserAgent,
}
if opt.KnownHostsFile != "" {
hostcallback, err := knownhosts.New(opt.KnownHostsFile)
if err != nil {
return nil, errors.Wrap(err, "couldn't parse known_hosts_file")
}
sshConfig.HostKeyCallback = hostcallback
}
if opt.UseInsecureCipher {
sshConfig.Config.SetDefaults()
sshConfig.Config.Ciphers = append(sshConfig.Config.Ciphers, "aes128-cbc", "aes192-cbc", "aes256-cbc", "3des-cbc")