ssh key 登录详解
2015-01-22 10:46:53 阿炯

SSH全称Secure SHell,顾名思义就是非常安全的Shell的意思,SSH协议是IETF(Internet Engineering Task Force)的Network Working Group所制定的一种协议。SSH的主要目的是用来取代传统的telnet和R系列命令(rlogin,rsh,rexec等)远程登陆和远程执行命令的工具,实现对远程登陆和远程执行命令加密。防止由于网络监听而出现的密码泄漏,对系统构成威胁。

SSH协议目前有SSH1和SSH2,SSH2协议兼容SSH1。目前实现SSH1和SSH2协议的主要软件有OpenSSH和SSH Communications Security Corporation 公司的SSH Communications 软件。前者是OpenBSD组织开发的一款免费的SSH软件,后者是商业软件,因此在linux、FreeBSD、OpenBSD、NetBSD等免费类UNIX系统种,通畅都使用OpenSSH作为SSH协议的实现软件。因此本文重点介绍一下OpenSSH的使用。需要注意的是OpenSSH和SSH Communications的登陆公钥/私钥的格式是不同的,如果想用SSH Communications产生的私钥/公钥对来登入到使用OpenSSH的linux系统需要对公钥/私钥进行格式转换。

在出现SSH之前,系统管理员需要登入远程服务器执行系统管理任务时,都是用telnet来实现的,telnet协议采用明文密码传送,在传送过程中对数据也不加密,很容易被不怀好意的人在网络上监听到密码。同样,在SSH工具出现之前R系列命令也很流行(由于这些命令都以字母r开头,故把这些命令合称为R系列命令R是remote的意思),比如rexec是用来执行远程服务器上的命令的,和telnet的区别是telnet需要先登陆远程服务器再实行相关的命令,而R系列命令可以把登陆和执行命令并登出系统的操作整合在一起。这样就不需要为在远程服务器上执行一个命令而特地登陆服务器了。

SSH是一种加密协议,不仅在登陆过程中对密码进行加密传送,而且对登陆后执行的命令的数据也进行加密,这样即使别人在网络上监听并截获了你的数据包,他也看不到其中的内容。OpenSSH已经是目前大多数linux和BSD操作系统(甚至cygwin)的标准组件,因此关于如何安装OpenSSH本文就不再叙述了,如果不出意外,你的系统上必定已经安装好了OpenSSH。

SSH发展历史

SSH1.x是1995年由芬兰赫尔辛基大学研究员Tatu Ylönen提出用于替代Telnet等非安全协议的远程Shell协议。SSH1.x通过CRC-32避免数据被篡改,后来逐步演化为私有软件。

SSH2.x由IETF工作小组发布SSH-2标准。采用MD5和SHA-1实现通信的完整性,安全性优于SSH-1。

OpenSSH是目前最流行的SSH实现的开源版本,具有可移植性,一直维护并支持SSH-2协议,目前很多操作系统中默认安装的版本。

SSH加密原理

互联网上的数据传输,若未经加密,请求可能会被其他恶意拦截轻松获取账号密码等信息,可通过数据加密的方式进行避免。加密的方式主要有两种:

1).对称加密(秘钥加密),即客户端和服务端使用同一套秘钥对数据进行加密和解密,对称加密的加密强度高,破解难度大。但是在多个客户端和服务端安全的保存秘钥是一个比较困难的操作,一个秘钥被泄露,则整个系统会失去安全性。

2).非对称加密(公钥加密),为解决一个秘钥的问题,非对称加密应运而生。非对称加密有一个公钥和一个私钥,公钥加密后的数据只能通过对应的私钥解密(反之亦然),而通过公钥推出私钥的可能性微乎其微。SSH即通过非对称加密完成用户登录。


OpenSSH软件包包含以下命令:
sshd -- SSH服务端程序

sftp-server -- SFTP服务端程序(类似FTP但提供数据加密的一种协议)

scp -- 非交互式sftp-server的客户端,用来向服务器上传/下载文件

sftp -- 交互式sftp-server客户端,用法和ftp命令一样。

slogin -- ssh的别名

ssh -- SSH协议的客户端程序,用来登入远程系统或远程执行命令

ssh-add -- SSH代理相关程序,用来向SSH代理添加dsa key

ssh-agent -- ssh代理程序

ssh-keyscan -- ssh public key 生成器


SSH工作流程

从客户端的角度来看,SSH提供两种级别的安全验证。分别为基于口令(密码)的安全验证和基于公钥的安全验证。

密码登录:密码登录流程如下图所示。


Server收到Client用户的登录请求,Server将自己的公钥发送给用户;
Client使用公钥将自己的密码加密
Client将加密后的数据发送至Server端
Server端使用对应的私钥解密数据,然后验证其合法性
如果密码正确,Server同意用户登录

私钥是Server端独有的,从而保证了网络传输过程中登录数据的安全性。但是实施的过程中存在一个风险:比如攻击者插在用户与远程主机间,冒充Server端将伪造的公钥发送给用户,即可获取用户的密码登录远程主机。这就是所谓的中间人攻击。

SSH设计通过口令确认的方式避免中间人攻击。如果用户是第一次登录Server,系统会出现如下提示:
ssh xxx@host
The authenticity of host 'host (xx.xx.xx.xx)' can't be established.
ECDSA key fingerprint is SHA256:WfEzXxsHzckXYaVA7RGrs1C1m2SVYa9LnfGro0SiOBQ.
Are you sure you want to continue connecting (yes/no)?

提示的信息主要表达的意思是:“无法确认主机host的真实性,其公钥指纹为xxx,是否继续登录?”由于公钥长度较长难以比对,提示信息中将其经过计算转换为相应的指纹便于比较。而为确保用户能比对公钥指纹,Server需在自己的网站上贴出自己的公钥指纹用于用户核对。

若用户同意连接该Server后,系统会提示用户该host已被确认并被追加到文件known_hosts文件中以便下次登录时跳过警告,然后即可输入密码按上述流程登录。

每个SSH用户(client端)都有自己的known_hosts文件, 此外系统也有一个这样的文件,通常是/etc/ssh/ssh_known_hosts或在用户的家目录下,保存一些对所有用户都可信赖的远程主机的公钥。

公钥登录:密码登录的一个问题在于,每次登录都要输入密码。为避免多次登录的麻烦,SSH提供了另一种可以免密的登录方式:公钥登录。


Client将自己的公钥存放在Server端,追加到authorized_keys文件中。
Server端接收到Client的连接请求后,会在authorized_keys中匹配到Client的公钥pubKey,并生成随机数R,用Client的公钥对该随机数进行加密得到pubKey(R),然后将加密后信息发送给Client。
Client端通过私钥进行解密得到随机数R,然后对随机数R和本次会话的SessionKey利用MD5生成摘要Digest1,发送给Server端。
Server端会也会对R和SessionKey利用同样摘要算法生成Digest2。
Server端会最后比较Digest1和Digest2是否相同,完成认证过程。

此后登录服务器就不再需要密码。

SSH密钥相关工具

依托于不同的操作系统,SSH密钥生成和客户端登录各有其不同的工具。Linux系统基本上都自带了相关的工具,Windows系统中有Putty、Xshell等工具。


SSH密钥格式

由SSH的发展历史可见,SSH有SSH1.x、SSH2.x(IETF)、openssh等不同的版本,因此也定义了不同的密钥格式。puttygen.exe可生成IETF格式的密钥,ssh-kengen生成openssh格式的密钥,xshell则可选择所需格式。

SSH1格式
公钥格式为所有字段以单个空格符分隔,各字段依次为选项、位数、指数、系数、注释。第一个字段是可选的,表示该条目(行)是否以数字开头,选项字段不会以数字开头。最后一个字段注释,如果在生成密钥时没有给定注释,默认注释为密钥的创建者(一般就是 username@hostname 这种格式),注释仅仅是提供给用户查看密钥时作为一个辨识标记,在 SSH 使用中没有任何作用。

1024 35
...一长串的数字...
freeoa@test.com

IETF格式
---- BEGIN SSH2 PUBLIC KEY ----
...一长串英文及数字字符...
---- END SSH2 PUBLIC KEY ----

OpenSSH格式
公钥格式为所有字段以单个空格符分隔,各字段依次为选项、密钥类型(keytype)、base64编码后的密钥、注释。第一个字段是可选的,表示该条目(行)是否以数字开头,选项字段不会以数字开头。最后一个字段注释,如果在生成密钥时没有给定注释,默认注释为密钥的创建者(一般就是 username@hostname 这种格式),注释仅仅是提供给用户查看密钥时作为一个辨识标记,在 SSH 使用中没有任何作用。


SSH最常用的使用方式是代替telnet进行远程登陆。不同于telnet的密码登陆,SSH还同时支持Publickey、Keybord Interactive、GSSAPI等多种登入方式,不像telnet那样只有输入系统密码一种途径。目前最常用的登陆方式还是传统的Password方式和Publickey方式登陆。下面以Redhat AS4为例,举例说明这两种登陆方式的用法。

[root@mail ~]# ssh 172.18.6.227
 The authenticity of host ’172.18.6.227 (172.18.6.227)’ can’t be established.
 RSA key fingerprint is 43:80:f2:e1:9b:b6:6e:c0:e2:dd:57:8f:ed:89:b3:81.
 Are you sure you want to continue connecting (yes/no)? yes
 Warning: Permanently added ’172.18.6.227′ (RSA) to the list of known hosts.
root@172.18.6.227‘s password:
Last login: Thu Jul 12 18:47:47 2007 from 172.18.6.130

第一次登陆后,ssh就会把登陆的ssh指纹存放在用户home目录的.ssh目录的know_hosts文件中,如果远程系统重装过系统,ssh指纹已经改变,你需要把 .ssh 目录下的know_hosts中的相应指纹删除,再登陆回答yes,方可登陆。请注意.ssh目录是开头是”.”的隐藏目录,需要ls –a参数才能看到。而且这个目录的权限必须是700,并且用户的home目录也不能给其他用户写权限,否则ssh服务器会拒绝登陆。如果发生不能登陆的问题,请察看服务器上的日志文件/var/log/secure。通常能很快找到不能登陆的原因。

ssh远程执行命令:
[root@mail ~]# ssh 172.18.6.227 ls -l /
root@172.18.6.227‘s password:
total 1244
 drwxr-xr-x 2 root root 4096 Jun 26 04:02 bin
 drwxr-xr-x 4 root root 4096 Mar 29 11:17 boot
 drwxr-xr-x 2 root root 4096 Jan 25 11:26 command
 drwxr-xr-x   15 root root 4096 Jun 12 20:09 data
 drwxr-xr-x 9 root root 5360 Jul  2 13:38 dev
 drwxr-xr-x   87 root root   12288 Jul 11 04:02 etc
 drwxr-xr-x   20 root root 4096 Apr 10 10:54 home
 drwxr-xr-x 2 root root 4096 Aug 13  2004 initrd

输入正确的密码后,ssh会链接远程服务器的sshd服务器程序,然后执行远程服务器上的ls –l /命令 ,并把输入结果传到本地服务器。相当于你先登陆到远程服务器,然后再实行命令ls –l /,最后再登出服务器。需要提醒的是,如果你需要登陆服务器并执行不止一个命令,必须要把命令用单引号或双引号引起来:
ssh 172.18.6.227 “cd /root && ls “

ssh的远程实行命令的功能是用来代替原始的R系列命令的,在ssh出现之前系统管理员们不得不用rexec, rsh等不安全的远程执行命令工具来完成同样的操作。这个功能在管理大批机器的时候是非常有用的,比如我要重启10.0.0.0/24网段内所有的服务器,只要输入一条命令:

 for i in $(seq 1 254) ; do  ssh 10.0.0.${i} reboot ; done

就可以完成重启所有服务器的操作,也许你会说,这要虽然不需要再登陆每一台服务器了,但是还是要每次输入密码,多麻烦啊。别急,下面要讲的用ssh public key方式登陆就是要解决问题。

采用public key登录

openssh的ssh-keygen命令用来产生这样的私钥和公钥。

 [root@mail ~]# ssh-keygen -b 1024 -t dsa -C user@freeoa.net
 Generating public/private dsa key pair.
 #提示正在生成,如果选择4096长度,可能需要较长时间
 Enter file in which to save the key (/root/.ssh/id_dsa):
 #询问把公钥和私钥放在那里,回车用默认位置即可
 Enter passphrase (empty for no passphrase):
 #询问输入私钥密语,为了实现自动登陆,应该不要密语,直接回车
 Enter same passphrase again:
 #再次提示输入密语,再次直接回车
 Your identification has been saved in /root/.ssh/id_dsa.
 Your public key has been saved in /root/.ssh/id_dsa.pub.
 #提示公钥和私钥已经存放在/root/.ssh/目录下
 The key fingerprint is:
 71:e5:cb:15:d3:8c:05:ed:05:84:85:32:ce:b1:31:ce user@freeoa.net
 #提示key的指纹

说明:
-b 1024 采用长度为1024字节的公钥/私钥对,最长4096字节,一般1024或2048就可以了,太长的话加密解密需要的时间也长。
-t dsa  采用dsa加密方式的公钥/私钥对,除了dsa还有rsa方式,rsa方式最短不能小于768字节长度。
-C user@freeoa.net 对这个公钥/私钥对的一个注释和说明,一般用所有人的邮件代替。可以省略不写,更多其他参数请man ssh-keygen。

 [root@mail ~]# ls -l /root/.ssh
 total 16
 -rw——-  1 root root 668 Jul 12 20:07 id_dsa
 -rw-r–r–  1 root root 611 Jul 12 20:07 id_dsa.pub
 -rw-r–r–  1 root root 222 Jul 12 19:37 known_hosts

产生的公钥/私钥文件在用户home目录的.ssh目录下,其中id_dsa.pub是公钥,把产生的公钥上传到需要登陆的服务器的对应用户目录的home目录的.ssh目录下,再一次强调用户自己的目录(home目录)必须不能有其他人可写的权限,.ssh目录的权限必须是700,即除了用户自己,其他人没有任何读写察看该目录的权限,否则ssh服务器会拒绝登陆。ssh默认的公钥文件是用户home目录下的.ssh目录下的authorized_keys文件,因此需要把产生的公钥以这个文件名放到服务器的/root/.ssh/目录下,这个文件中可以存放多个客户端的公钥文件,就好比一个大门上可以上很多锁,可以有不同的钥匙来尝试开锁,只要有一个锁被打开了,门就可以打开了。放到服务器上应该是这样子的:

私钥必须是600权限,否则ssh服务器会拒绝用户登陆。

大致就是这个样子了。现把/etc/ssh/ssh_config 和 /etc/ssh/sshd_config的配置说下。

/etc/ssh/ssh_config:

 Host *
 选项“Host”只对能够匹配后面字串的计算机有效。“*”表示所有的计算机。

 ForwardAgent no
 “ForwardAgent”设置连接是否经过验证代理(如果存在)转发给远程计算机。

 ForwardX11 no
 “ForwardX11”设置X11连接是否被自动重定向到安全的通道和显示集(DISPLAY set)。

 RhostsAuthentication no
 “RhostsAuthentication”设置是否使用基于rhosts的安全验证。

 RhostsRSAAuthentication no
 “RhostsRSAAuthentication”设置是否使用用RSA算法的基于rhosts的安全验证。

 RSAAuthentication yes
 “RSAAuthentication”设置是否使用RSA算法进行安全验证。

 PasswordAuthentication yes
 “PasswordAuthentication”设置是否使用口令验证。

 FallBackToRsh no
 “FallBackToRsh”设置如果用ssh连接出现错误是否自动使用rsh。

 UseRsh no
 “UseRsh”设置是否在这台计算机上使用“rlogin/rsh”。

 BatchMode no
 “BatchMode”如果设为“yes”,passphrase/password(交互式输入口令)的提示将被禁止。当不能交互式输入口令的时候,这个选项对脚本文件和批处理任务十分有用。

 CheckHostIP yes
 “CheckHostIP”设置ssh是否查看连接到服务器的主机的IP地址以防止DNS欺骗。建议设置为“yes”。

 StrictHostKeyChecking no
 “StrictHostKeyChecking”如果设置成“yes”,ssh就不会自动把计算机的密匙加入“$HOME/.ssh/known_hosts”文件,并且一旦计算机的密匙发生了变化,就拒绝连接。

 IdentityFile ~/.ssh/identity
 “IdentityFile”设置从哪个文件读取用户的RSA安全验证标识。

 Port 22
 “Port”设置连接到远程主机的端口。

 Cipher blowfish
 “Cipher”设置加密用的密码。

 EscapeChar ~
 “EscapeChar”设置escape字符。

/etc/ssh/sshd_config:

 Port 22
 “Port”设置sshd监听的端口号。

 ListenAddress 192.168.1.1
 “ListenAddress”设置sshd服务器绑定的IP地址。

 HostKey /etc/ssh/ssh_host_key

 “HostKey”设置包含计算机私人密匙的文件。

 ServerKeyBits 1024
 “ServerKeyBits”定义服务器密匙的位数。

 LoginGraceTime 600
 “LoginGraceTime”设置如果用户不能成功登录,在切断连接之前服务器需要等待的时间(以秒为单位)。

 KeyRegenerationInterval 3600
 “KeyRegenerationInterval”设置在多少秒之后自动重新生成服务器的密匙(如果使用密匙)。重新生成密匙是为了防止用盗用的密匙解密被截获的信息。

 PermitRootLogin no
 “PermitRootLogin”设置root能不能用ssh登录。这个选项一定不要设成“yes”。

 IgnoreRhosts yes
 “IgnoreRhosts”设置验证的时候是否使用“rhosts”和“shosts”文件。

 IgnoreUserKnownHosts yes
 “IgnoreUserKnownHosts”设置ssh daemon是否在进行RhostsRSAAuthentication安全验证的时候忽略用户的“$HOME/.ssh/known_hosts”

 StrictModes yes
 “StrictModes”设置ssh在接收登录请求之前是否检查用户家目录和rhosts文件的权限和所有权。这通常是必要的,因为新手经常会把自己的目录和文件设成任何人都有写权限。

 X11Forwarding no
 “X11Forwarding”设置是否允许X11转发。

 PrintMotd yes
 “PrintMotd”设置sshd是否在用户登录的时候显示“/etc/motd”中的信息。

 SyslogFacility AUTH
 “SyslogFacility”设置在记录来自sshd的消息的时候,是否给出“facility code”。

 LogLevel INFO
 “LogLevel”设置记录sshd日志消息的层次。INFO是一个好的选择。查看sshd的man帮助页,已获取更多的信息。

 RhostsAuthentication no
 “RhostsAuthentication”设置只用rhosts或“/etc/hosts.equiv”进行安全验证是否已经足够了。

 RhostsRSAAuthentication no
 “RhostsRSA”设置是否允许用rhosts或“/etc/hosts.equiv”加上RSA进行安全验证。

 RSAAuthentication yes
 “RSAAuthentication”设置是否允许只有RSA安全验证。

 PasswordAuthentication yes
 “PasswordAuthentication”设置是否允许口令验证。

 PermitEmptyPasswords no
 “PermitEmptyPasswords”设置是否允许用口令为空的帐号登录。

 AllowUsers admin
 “AllowUsers”的后面可以跟着任意的数量的用户名的匹配串(patterns)或user@host这样的匹配串,这些字符串用空格隔开。主机名可以是DNS名或IP地址。

将SSH2兼容格式的公钥转换成为Openssh兼容格式

 ssh-keygen -i -f Identity.pub >> /root/.ssh/authorized_keys2

本文源自:互联网