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:
parent
66def93373
commit
6dc28ef50a
2 changed files with 89 additions and 0 deletions
|
@ -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")
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue