Saturday, October 18, 2008

How to disable SSH host key checking

Remote login using the SSH protocol is a frequent activity in today's internet world. With the SSH protocol, the onus is on the SSH client to verify the identity of the host to which it is connecting. The host identify is established by its SSH host key. Typically, the host key is auto-created during initial SSH installation setup.

By default, the SSH client verifies the host key against a local file containing known, trustworthy machines. This provides protection against possible Man-In-The-Middle attacks. However, there are situations in which you want to bypass this verification step. This article explains how to disable host key checking using OpenSSH, a popular Free and Open-Source implementation of SSH.

When you login to a remote host for the first time, the remote host's host key is most likely unknown to the SSH client. The default behavior is to ask the user to confirm the fingerprint of the host key.
$ ssh peter@192.168.0.100
The authenticity of host '192.168.0.100 (192.168.0.100)' can't be established.
RSA key fingerprint is 3f:1b:f4:bd:c5:aa:c1:1f:bf:4e:2e:cf:53:fa:d8:59.
Are you sure you want to continue connecting (yes/no)?

If your answer is yes, the SSH client continues login, and stores the host key locally in the file ~/.ssh/known_hosts. You only need to validate the host key the first time around: in subsequent logins, you will not be prompted to confirm it again.

Yet, from time to time, when you try to remote login to the same host from the same origin, you may be refused with the following warning message:
$ ssh peter@192.168.0.100
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that the RSA host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
3f:1b:f4:bd:c5:aa:c1:1f:bf:4e:2e:cf:53:fa:d8:59.
Please contact your system administrator.
Add correct host key in /home/peter/.ssh/known_hosts to get rid of this message.
Offending key in /home/peter/.ssh/known_hosts:3
RSA host key for 192.168.0.100 has changed and you have requested strict checking.
Host key verification failed.$

There are multiple possible reasons why the remote host key changed. A Man-in-the-Middle attack is only one possible reason. Other possible reasons include:
  • OpenSSH was re-installed on the remote host but, for whatever reason, the original host key was not restored.
  • The remote host was replaced legitimately by another machine.

If you are sure that this is harmless, you can use either 1 of 2 methods below to trick openSSH to let you login. But be warned that you have become vulnerable to man-in-the-middle attacks.

The first method is to remove the remote host from the ~/.ssh/known_hosts file. Note that the warning message already tells you the line number in the known_hosts file that corresponds to the target remote host. The offending line in the above example is line 3("Offending key in /home/peter/.ssh/known_hosts:3")

You can use the following one liner to remove that one line (line 3) from the file.
$ sed -i 3d ~/.ssh/known_hosts

Note that with the above method, you will be prompted to confirm the host key fingerprint when you run ssh to login.

The second method uses two openSSH parameters:
  • StrictHostKeyCheckin, and

  • UserKnownHostsFile.

This method tricks SSH by configuring it to use an empty known_hosts file, and NOT to ask you to confirm the remote host identity key.
$ ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no peter@192.168.0.100
Warning: Permanently added '192.168.0.100' (RSA) to the list of known hosts.
peter@192.168.0.100's password:

The UserKnownHostsFile parameter specifies the database file to use for storing the user host keys (default is ~/.ssh/known_hosts).

The /dev/null file is a special system device file that discards anything and everything written to it, and when used as the input file, returns End Of File immediately.

By configuring the null device file as the host key database, SSH is fooled into thinking that the SSH client has never connected to any SSH server before, and so will never run into a mismatched host key.

The parameter StrictHostKeyChecking specifies if SSH will automatically add new host keys to the host key database file. By setting it to no, the host key is automatically added, without user confirmation, for all first-time connection. Because of the null key database file, all connection is viewed as the first-time for any SSH server host. Therefore, the host key is automatically added to the host key database with no user confirmation. Writing the key to the /dev/null file discards the key and reports success.

Please refer to this excellent article about host keys and key checking.

By specifying the above 2 SSH options on the command line, you can bypass host key checking for that particular SSH login. If you want to bypass host key checking on a permanent basis, you need to specify those same options in the SSH configuration file.

You can edit the global SSH configuration file (/etc/ssh/ssh_config) if you want to make the changes permanent for all users.

If you want to target a particular user, modify the user-specific SSH configuration file (~/.ssh/config). The instructions below apply to both files.

Suppose you want to bypass key checking for a particular subnet (192.168.0.0/24).

Add the following lines to the beginning of the SSH configuration file.
Host 192.168.0.*
StrictHostKeyChecking no
UserKnownHostsFile=/dev/null

Note that the configuration file should have a line like Host * followed by one or more parameter-value pairs. Host *means that it will match any host. Essentially, the parameters following Host * are the general defaults. Because the first matched value for each SSH parameter is used, you want to add the host-specific or subnet-specific parameters to the beginning of the file.

As a final word of caution, unless you know what you are doing, it is probably best to bypass key checking on a case by case basis, rather than making blanket permanent changes to the SSH configuration files.

If you make it this far in the article, you may find the following more recent ssh articles interesting:

Allow root ssh login with public key authentication
How to auto fill in ssh client parameters
One-liner to shutdown remote host
X11 Forwarding over SSH

66 comments:

  1. Thanks Buddy for this article..
    I was desperately looking for a solution to this and it worked as a charm.

    Cheers !
    @$h

    ReplyDelete
  2. Wish I had read further, used vi +linNum to get rid of my offending entries 8^0
    Great advice, tnx for the article.

    ReplyDelete
  3. Where have you been all my life?

    This is perfect! I've NEVER seen a reference to:UserKnownHostsFile=/dev/null!

    Perfect! thanks again!

    ReplyDelete
  4. Why not just use
    NoHostAuthenticationForLocalhost yes
    ?

    ReplyDelete
  5. Thanks a lot
    This was extremely useful for me ..:)

    ReplyDelete
  6. Excellent tutorial . 5 stars.
    i made a script to do this for "problematic hosts" , just copy and paste into edit /bin/sshu

    ----START-COPY----
    #

    ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "$@"'
    ---SNIP-----

    Usage -
    chmod 775 /bin/sshu

    sshu myhost

    ReplyDelete
  7. @Chetan: you can achieve something similar by using the "host" keyword in ~/.ssh/config

    grep for "restricts the following declarations" at http://man.sourcentral.org/ubuntu810/5+ssh_config

    @peter: instead of the sed one-liner, you could use 'ssh-keygen -R foo'

    regardless, thanks for the informative post!

    -tyler

    ReplyDelete
  8. Thanks a lot Peter, i have aliased it in .bashrc file, as most of the hosts i connect are local and harmless.

    alias ssh="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"

    Also i would like to provide the password as an argument to ssh, is there an option to do this, can you please help?

    ReplyDelete
  9. Thanks a lot! This frees me from the burden of "vim .ssh/known_hosts +n", after every reinstallations during development.

    ReplyDelete
  10. Arun,

    You cannot pass the password as a command-line argument to ssh. I can think of 2 ways for a password-less login via ssh.

    One is bypass the use of password for authentication, and instead use a public key. The second is to script the ssh login (password and all) using a scripting tool called "expect".

    Peter

    ReplyDelete
  11. Yoiks... there are pretty serious security issues with blindly turning off host-key checking.

    If you want to remove an old stale key the easiest way is to run "ssh-keygen -R hostname".

    If your admins keep changing keys on and aren't willing to set up SSH fingerprint checking with DNS then I would recommend you use public key authentication as this offers some protection and is so much easier to use...

    If you really don't give a sausage about security then why not turn on telnet and leave root passwords blank?

    ReplyDelete
  12. This was really helpfull.

    Thanks,
    VIKAS
    Sr. Unix System Admin

    ReplyDelete
  13. Very useful. Bypassing host fingerprint checks is hardly the same as turning on telnet and leaving root password blank. Dramatic much?

    ReplyDelete
  14. Extremely helpful. Was looking for a way to remove the bottleneck of only having a single SSH access point on the network from the outside. Now I'm able to SSH into any workstation on the network without having to remove my known_hosts all the time. Thanks!

    ReplyDelete
  15. Excellent article.

    Is it possible to keep the list of hosts that I have visited, while disabling warnings on host key change? The logic behind is that I can then tab-complete hosts with bash completion if in .ssh/known_hosts.

    ReplyDelete
  16. I have a virtual IP targetting one of several hosts. All these hosts have different fingerprints.

    Everytime the virtual IP changes its targets, i get this "offending key" message, because the ssh handshake gets the fingerprint of the targetted host.

    Is it possible to provide a list of potential fingerprints in the known_hosts file? I need strong security.

    thanks for your advice

    ReplyDelete
  17. Excellent thanks.

    We're constantly rebuilding the firmware on test product and this solves the problem.

    Bypassed checking for all host on our test client subnet.

    ReplyDelete
  18. To the guy with the multiple servers:

    If you have multiple machines that can be reached with the same name, such as a load balanced pair of webservers, then include both host keys under the shared name. The ssh client will check all matches until it finds one, so you can share a common DNS name without sharing the host key itself.

    Copied from the article recommended in the text above: http://www.securityfocus.com/infocus/1806

    ReplyDelete
  19. thanks alot mr commandow. this was a major pain in the a** while working with tunnels..

    ReplyDelete
  20. Thanks for the sed tip - very useful.

    ReplyDelete
  21. Excellent article. Infinitely useful! Thanks for posting!

    ReplyDelete
  22. Thanks, this helped me a lot :)
    TIP: it is possible to do the same thing on OpenSSH for Windows just replacing "/dev/null" for "NUL".
    Bye.

    ReplyDelete
  23. I think it is a lot better to use
    StrictHostKeyChecking=ask.

    The you will be asked each time the key has changed, and if you know that the key is correct you can answer "yes".

    ReplyDelete
  24. Excellent solution! Helped me write a nice command line utility, and doesn't leave a mess on my system.

    ReplyDelete
  25. Thanks. This was useful in a case I just had. It also works with parallel-ssh utility with -O for getting at many clients quick and effective.

    ReplyDelete
  26. Just found this -- many thanks!

    I combined several of the suggestions and made this bash function:

    rssh () {
    ssh-keygen -R `echo ${!#} | sed -e 's/.*@//'`
    ssh $*
    }

    I put StrictHostKeyChecking no in my .ssh/config, but use the regular known_hosts file.

    I can "ssh user@host" or "ssh -l user host" and new hosts get added.
    If the host key changes, I just run "r!!" (which prepends "r" to the previous command) and the rssh function will remove it from known_hosts and ssh again.

    ReplyDelete
  27. Most excellent. I have a jailbroken iPhone that is a pain to get into when it gets a different IP address on a specific subnet every time... I use this trick in conjunction with ssh-agent. Voila!

    Thanks!

    ReplyDelete
  28. thank you very much

    ReplyDelete
  29. if you're okay with never saving hosts, just run:

    rm ~/.ssh/known_hosts
    touch ~/.ssh/known_hosts
    chmod 000 ~/.ssh/known_hosts

    that way the openssh client will fail every time it tries to read/write to it.

    ReplyDelete
  30. I'd like to point out that this works for "sed" as well, and saved me a lot of busywork. :-)

    ReplyDelete
  31. I do a lot of configuring clusters with frequent reimaging and reconfiguring of nodes in a test environment and use keyless ssh for all kinds of remote command execution. Telnet would not cut it.

    There are other better tools, but keyless ssh is usually the first step for me in getting things set up.

    ReplyDelete
  32. Exactly what I was looking for - thanks!

    ReplyDelete
  33. Thanks for the tips - this is useful when using resync with ssh through a tunnel - as the destination address is always the same (because the tunnel actually send the data to where you want it to go.)

    ReplyDelete
  34. awesome, cheers - the /dev/null trick was what I was missing... much easier than what I was thinking about :p
    Automated (re)connection to my dynamic IP is complete...

    ReplyDelete
  35. One year later ...still useful !

    Thanks a lot !

    ReplyDelete
  36. Yes! Just what I was looking for! Thanks! We re-image our lab machines as new builds are released, keeping the same IP information, this saved me some steps.

    ReplyDelete
  37. Very useful article, thanks a lot !

    ReplyDelete
  38. Very useful.
    Thanks a lot!

    just use [-o StrictHostKeyChecking=no] can skip the confirm prompt.

    ReplyDelete
  39. Thanks so much for this!

    ReplyDelete
  40. Wonderful.. Worked like a charm.. Thanks... Was looking for something like this for a very long time.. kind of annoying to see that message when you know what and where are you connecting.. :D

    ReplyDelete
  41. Very useful, thanks. I was automatizing a parallel task using ssh commands to create processes in parallel and this prompt-login was a hindrance. That was to the spot.

    ReplyDelete
  42. "a local file containing known, rustworthy machines"?!

    That made me laugh. Thanks for the tutorial

    ReplyDelete
  43. Thanks bud, this was exactly what I was looking for.

    ReplyDelete
  44. Thank you!
    And especially to the trick UserKnownHostsFile=/dev/null !

    That helped me a lot!

    ReplyDelete
  45. Holy crap thank you

    ReplyDelete
  46. This is brilliant, thanks for explanation!

    ReplyDelete
  47. Thanks a lot for posting this!! This is what I was looking for as I am connecting through USB to different devices so I don't need key checking for this host...

    ReplyDelete
  48. Thank You!!!!!

    typo here (missing 'g'):
    he second method uses two openSSH parameters:
    StrictHostKeyCheckin, and

    ReplyDelete
  49. Thanks for this great article. On my system there really is no 'telnet' alternative and some of ssh's well meaning makes it hard to use in scripts where the target machine is constantly being wiped. Obviously, this hack is only for those who understand all the implications...

    Thanks again!

    ReplyDelete
  50. This is blog is useful about security attacks.

    ReplyDelete
  51. Thank you for the article, as a guy having to work on more than 50 linux workstations I really appreciate the trick.

    ReplyDelete
  52. And five years after, this article is just as incredibly useful as it was from day #1.
    Thanks for solving this headache for me !

    ReplyDelete
  53. Dude, you rock.

    This works also with scp (secure copy from one ssh server to another) as follows:

    scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i /local/path/to/ /local/path/of/file/to/send/file.zip @:/remote/path/to/save/file

    ReplyDelete
  54. Dude, you rock.

    This works also with scp (secure copy from one ssh server to another) as follows:

    scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i /local/path/to/[remote-key.pem] /local/path/of/file/to/send/file.zip [remote user]@[remote_host]:/remote/path/to/save/file

    ReplyDelete
  55. Also, one more touch is the icing on the cake:

    -o LogLevel=quiet

    -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=quiet

    Lovely!

    ReplyDelete
  56. What if the source file for the scp is not local? The below doesn't seem to work:

    scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no [remote user]@[remote_host]:/remote/path/to/send/file.zip [remote user]@[remote_host]:/remote/path/to/save/file

    ReplyDelete
  57. Great post, thanks.

    On a MAC this doesn't work as written here. You need to add ' ' after the -i to ignore extensions. Otherwise you will get an error about "command c expects \ followed by text"

    cheers,
    john

    ReplyDelete
  58. This article is very useful. Thank you.

    ReplyDelete
  59. thanks, this was a big help!

    ReplyDelete
  60. there are pretty serious security issues with blindly turning off host-key checking.

    ReplyDelete
  61. Thanks a lot .. This is what I was looking for. It helped me to automate sftp by using shell script .

    ReplyDelete
  62. Thanks. This is great.

    ReplyDelete
  63. Gracias por el aporte, me ayudo 12 años después tu blog.

    ReplyDelete
  64. Thank you very much! Still helpfull (and nowhere else found) in 2020!

    ReplyDelete
  65. Thanks as well for the explanation and solution!
    Appreciate it!

    ReplyDelete