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" "github.com/rclone/rclone/lib/readers"
sshagent "github.com/xanzy/ssh-agent" sshagent "github.com/xanzy/ssh-agent"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/knownhosts"
) )
const ( const (
@ -86,6 +87,16 @@ in the new OpenSSH format can't be used.`,
Help: `Optional path to public key file. Help: `Optional path to public key file.
Set this if you have a signed certificate you want to use for authentication.` + env.ShellExpandHelp, 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", Name: "key_use_agent",
Help: `When set forces the usage of the ssh-agent. Help: `When set forces the usage of the ssh-agent.
@ -195,6 +206,7 @@ type Options struct {
KeyFile string `config:"key_file"` KeyFile string `config:"key_file"`
KeyFilePass string `config:"key_file_pass"` KeyFilePass string `config:"key_file_pass"`
PubKeyFile string `config:"pubkey_file"` PubKeyFile string `config:"pubkey_file"`
KnownHostsFile string `config:"known_hosts_file"`
KeyUseAgent bool `config:"key_use_agent"` KeyUseAgent bool `config:"key_use_agent"`
UseInsecureCipher bool `config:"use_insecure_cipher"` UseInsecureCipher bool `config:"use_insecure_cipher"`
DisableHashCheck bool `config:"disable_hashcheck"` DisableHashCheck bool `config:"disable_hashcheck"`
@ -414,6 +426,7 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
if opt.Port == "" { if opt.Port == "" {
opt.Port = "22" opt.Port = "22"
} }
sshConfig := &ssh.ClientConfig{ sshConfig := &ssh.ClientConfig{
User: opt.User, User: opt.User,
Auth: []ssh.AuthMethod{}, 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, 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 { if opt.UseInsecureCipher {
sshConfig.Config.SetDefaults() sshConfig.Config.SetDefaults()
sshConfig.Config.Ciphers = append(sshConfig.Config.Ciphers, "aes128-cbc", "aes192-cbc", "aes256-cbc", "3des-cbc") sshConfig.Config.Ciphers = append(sshConfig.Config.Ciphers, "aes128-cbc", "aes192-cbc", "aes256-cbc", "3des-cbc")

View File

@ -148,6 +148,57 @@ Note: the cert must come first in the file. e.g.
cat id_rsa-cert.pub id_rsa > merged_key cat id_rsa-cert.pub id_rsa > merged_key
``` ```
### Host key validation ###
By default rclone will not check the server's host key for validation. This
can allow an attacker to replace a server with their own and if you use
password authentication then this can lead to that password being exposed.
Host key matching, using standard `known_hosts` files can be turned on by
enabling the `known_hosts_file` option. This can point to the file maintained
by `OpenSSH` or can point to a unique file.
e.g.
```
[remote]
type = sftp
host = example.com
user = sftpuser
pass =
known_hosts_file = ~/.ssh/known_hosts
````
There are some limitations:
* `rclone` will not _manage_ this file for you. If the key is missing or
wrong then the connection will be refused.
* If the server is set up for a certificate host key then the entry in
the `known_hosts` file _must_ be the `@cert-authority` entry for the CA
* Unlike `OpenSSH`, the libraries used by `rclone` do not permit (at time
of writing) multiple host keys to be listed for a server. Only the first
entry is used.
If the host key provided by the server does not match the one in the
file (or is missing) then the connection will be aborted and an error
returned such as
NewFs: couldn't connect SSH: ssh: handshake failed: knownhosts: key mismatch
or
NewFs: couldn't connect SSH: ssh: handshake failed: knownhosts: key is unknown
If you see an error such as
NewFs: couldn't connect SSH: ssh: handshake failed: ssh: no authorities for hostname: example.com:22
then it is likely the server has presented a CA signed host certificate
and you will need to add the appropriate `@cert-authority` entry.
The `known_hosts_file` setting can be set during `rclone config` as an
advanced option.
### ssh-agent on macOS ### ### ssh-agent on macOS ###
Note that there seem to be various problems with using an ssh-agent on Note that there seem to be various problems with using an ssh-agent on
@ -320,6 +371,23 @@ Leave blank or set to false to enable hashing (recommended), set to true to disa
Here are the advanced options specific to sftp (SSH/SFTP Connection). Here are the advanced options specific to sftp (SSH/SFTP Connection).
#### --sftp-known-hosts-file
Optional path to known_hosts file.
Set this value to enable server host key validation.
Leading `~` will be expanded in the file name as will environment variables such as `${RCLONE_CONFIG_DIR}`.
- Config: known_hosts_file
- Env Var: RCLONE_SFTP_KNOWN_HOSTS_FILE
- Type: string
- Default: ""
- Examples:
- "~/.ssh/known_hosts"
- Use OpenSSH's known_hosts file
#### --sftp-ask-password #### --sftp-ask-password
Allow asking for SFTP password when needed. Allow asking for SFTP password when needed.