一、什么是 SSH ?
SSH(Secure SHell)是一种网络协议,顾名思义就是非常安全的shell,主要用于计算机间加密传输。早期,互联网通信都是基于明文通信,一旦被截获,内容就暴露无遗。1995年,芬兰学者Tatu Ylonen设计了SSH协议,将登录信息全部加密,成为互联网安全的一个基本解决方案,迅速在全世界获得推广,目前已经成为Linux系统的标准配置。SSH的主要目的是用来取代传统的telnet 和 R 系列命令(rlogin, rsh, rexec 等)远程登录和远程执行命令的工具,实现对远程登录和远程执行命令加密,防止由于网络监听而密码泄露问题。
需要指出的是,SSH 只是一种协议(规范),存在很多实现方式,既有商业实现,也有开源实现。
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系统需要对公钥/私钥进行格式转换。
OpenSSH 是一组用于安全地访问远程计算机的连接工具。 它可以作为 rlogin、 rsh rcp 以及 telnet 的直接替代品使用。 更进一步, 其他任何 TCP/IP 连接都可以通过 SSH 安全地进行隧道/转发。 OpenSSH 对所有的传输进行加密, 从而有效地阻止了窃听、 连接劫持, 以及其他网络级的攻击。
在出现SSH之前,系统管理员需要登入远程服务器执行系统管理任务时,都是用telnet 或者 rlogin 来实现的,telnet协议采用明文密码传送,在传送过程中对数据也不加密,很容易被不怀好意的人在网络会话中窃取到传输的用户名/密码和数据。同样,在SSH工具出现之前R系列命令也很流行(由于这些命令都以字母r开头,故把这些命令合称为R系列命令R是remote的意思),比如rexec是用来执行远程服务器上的命令的,和telnet的区别是telnet需要先登陆远程服务器再实行相关的命令,而R系列命令可以把登陆和执行命令并登出系统的操作整合在一起。这样就不需要为在远程服务器上执行一个命令而特地登陆服务器了。
SSH是一种加密协议,不仅在登陆过程中对密码进行加密传送,而且对登陆后执行的命令的数据也进行加密,这样即使别人在网络上监听并截获了你的数据包,他也看不到其中的内容。OpenSSH已经是目前大多数linux和BSD操作系统(甚至cygwin)的标准组件,因此关于如何安装OpenSSH本文就不再叙述了,如果不出意外,你的系统上必定已经安装好了OpenSSH。
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-keygen -- ssh public key 生成器
SSH最常用的使用方式是代替telnet进行远程登陆。不同于telnet的密码登陆,SSH还同时支持Publickey、Keybord Interactive、GSSAPI等多种登入方式,不像telnet那样只有输入系统密码一种途径。目前最常用的登陆方式还是传统的Password方式 和 Publickey方式登陆。
SSH提供两种方式的登录验证:
1、密码验证:以服务器中本地系统用户的登录名称,密码进行验证。
2、秘钥对验证:要求提供相匹配的秘钥信息才能通过验证。通常先在客户机中创建一对秘钥文件(公钥和私钥),然后将公钥文件放到服务器中的指定位置。
注意:当密码验证和私钥验证都启用时,服务器将优先使用秘钥验证。
二、基本使用
1、用于代替 telnet, 进行远程登录。 # ssh [email protected] 2、如果bending用户名与远程主机用户名一致,登录时可以省略用户名。 # ssh host 3、ssh 协议默认端口 22,也就是缺省情况是连接远程主机的22号端口,使用 -p 参数可以指定端口号 # ssh -p 2222 [email protected] 4、ssh 远程执行命令 # ssh [email protected] ‘ls -l /etc‘ 输入正确的密码后,ssh会链接远程服务器的sshd服务器程序,然后执行远程服务器上的 ls –l /etc 命令 ,并把输入结果传到本地服务器。相当于你先登陆到远程服务器,然后再实行命令ls –l /,最后再登出服务器。
三、中间人攻击
SSH之所以能够保证安全,原因在于它采用了公钥加密。
整个过程是这样的:
(1)远程主机收到用户的登录请求,把自己的公钥发给用户。
(2)用户使用这个公钥,将登录密码加密后,发送回来。
(3)远程主机用自己的私钥,解密登录密码,如果密码正确,就同意用户登录。
这个过程本身是安全的,但是实施的时候存在一个风险:如果有人截获了登录请求,然后冒充远程主机,将伪造的公钥发给用户,那么用户很难辨别真伪。因为不像https协议,SSH协议的公钥是没有证书中心(CA)公证的,也就是说,都是自己签发的。
可以设想,如果攻击者插在用户与远程主机之间(比如在公共的wifi区域),用伪造的公钥,获取用户的登录密码。再用这个密码登录远程主机,那么SSH的安全机制就荡然无存了。这种风险就是著名的"中间人攻击"(Man-in-the-middle attack)。
SSH协议是如何应对的呢?
如果你是第一次通过ssh登录远程主机,会出现下面的提示:
# ssh [email protected] The authenticity of host ‘host (12.18.429.21)‘ can‘t be established. RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d. Are you sure you want to continue connecting (yes/no)?
这段话的意思是,无法确认host主机的真实性,只知道它的公钥指纹,问你还想继续连接吗?
所谓"公钥指纹",是指公钥长度较长(这里采用RSA算法,长达1024位),很难比对,所以对其进行MD5计算,将它变成一个128位的指纹。上例中是98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d,再进行比较,就容易多了。
很自然的一个问题就是,用户怎么知道远程主机的公钥指纹应该是多少?回答是没有好办法,远程主机必须在自己的网站上贴出公钥指纹,以便用户自行核对。
假定经过风险衡量以后,用户决定接受这个远程主机的公钥。
Are you sure you want to continue connecting (yes/no)? yes
系统会出现一句提示,表示host主机已经得到认可。
Warning: Permanently added ‘host,12.18.429.21‘ (RSA) to the list of known hosts.
当远程主机的公钥被接受以后,它就会被保存在用户home目录的 $HOME/.ssh/known_hosts 文件之中。下次再连接这台远程主机,系统就会认出它的公钥已经保存在本地了,从而跳过警告部分,直接提示输入密码。
出现“WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED 警告”无法建立ssh连接。如果远程系统重装过系统, ssh指纹已经改变,你需要把 .ssh 目录下的 know_hosts 文件中相应远程主机IP一致的指纹删除,再通过ssh登录一次回答 yes,重新认证一次方可登录。注意 .ssh 目录是以 "." 开头的隐藏目录,需要 # ls -a 参数才能看到。
而且这个目录的权限必须是700,并且用户的home目录也不能给其他用户写权限,否则ssh服务器会拒绝登陆。如果发生不能登陆的问题,请察看服务器上的日志文件/var/log/secure。通常能很快找到不能登陆的原因。
每个SSH用户都有自己的 known_hosts 文件,此外系统也有一个这样的文件,通常是 /etc/ssh/ssh_known_hosts,保存一些对所有用户都可信赖的远程主机的公钥。
四、公钥登录
使用密码登录,每次都必须输入密码,感觉太浪费时间,而且非常麻烦。尤其是密码超级复杂,维护的服务器又比较多的情况下。好在SSH还提供了公钥(public key)登录,可以省去输入密码的步骤。
所谓"公钥登录",原理很简单,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。
基于密钥的安全验证必须为用户自己创建一对密钥,并把共有的密钥放在需要访问的服务器上。当需要连接到SSH服务器上时,客户端软件就会向服务器发出请求,请求使用客户端的密钥进行安全验证。服务器收到请求之后,先在该用户的根目录下寻找共有密钥,然后把它和发送过来的公有密钥进行比较。如果两个密钥一致,服务器就用公有的密钥加密“质询”,并把它发送给客户端软件(putty,xshell等)。客户端收到质询之后,就可以用本地的私人密钥解密再把它发送给服务器,这种方式是相当安全的。
因为puttygen生成的密钥有问题可能会出现:“Server refused our key”,最好使用XShell生成密钥或者在远程Linux VPS/服务器生成密钥。
1、在Linux下通过 ssh-keygen生成密钥
这种方法要求用户必须提供自己的公钥。如果没有现成的,可以直接用ssh-keygen生成一个:
第一步:生成密钥文件
1、在本地生成一对密钥文件(公钥和私钥) # ssh-keygen # 以上命令等价于 ssh-keygen -t rsa # -t:指定密钥的类型,默认为SSH-2 的rsa类型; [[email protected] ~]# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): # 如果设置密码,通过密钥连接也需要输入密码 Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub. The key fingerprint is: 35:dd:d8:49:05:be:e9:7e:89:b7:86:e2:96:17:a0:2b [email protected] The key‘s randomart image is: +--[ RSA 2048]----+ | oo.| | . * . | | o o = | | . o o | | S . . o | | . o | | . . = . | | E . + = +. | | . o.o +o. | +-----------------+
运行上面的命令以后,系统会出现一系列提示,可以一路回车。特别说明,其中有一个问题是,要不要对私钥设置口令(passphrase),如果担心私钥的安全,这里可以设置一个,但是设置之后,利用私钥连接也需要输入密码。
运行结束以后,在 $HOME/.ssh/ 目录下,会新生成两个文件:id_rsa.pub 和 id_rsa。前者是你的公钥,后者是你的私钥。再一次强调用户自己的目录(~/.ssh)必须不能有其他人可写的权限, .ssh 目录的权限必须是 700, chmod 700 ~/.ssh 必须。否则ssh服务器会拒绝登录。
sshd服务器端默认的公钥文件是用户home目录下的.ssh目录下的 authorized_keys 文件,因此需要把产生的公钥以这个文件名放到服务器的 $HOME/.ssh/ 目录下,这个文件中可以存放多个客户端的公钥文件,就好比一个大门上可以上很多锁,可以有不同的钥匙来尝试开锁,只要有一个锁被打开了,门就可以打开了。~/.ssh/authorized_keys 必须是600权限,否则ssh服务器会拒绝用户登陆。chmod 600 ~/.ssh/authorized_keys
第二步:把生成的密钥文件上传到远程主机
这时再输入下面的命令,将生成的公钥传送到远程主机host上面对应用户home目录下的 .ssh 目录下:
2、将公钥上传到欲远程连接的主机上面 # ssh-copy-id [email protected]
好了,经过以上两步之后,从此你再登录,就不需要输入密码了。此命令执行后,远程主机直接将用户的公钥保存在 ~/.ssh/authorized_keys 文件中。
如果还是不行,就打开远程主机的 /etc/ssh/sshd_config 这个文件,检查下面几行前面"#"注释是否取掉。
然后重新启动远程主机的sshd服务:
## RHEL / CentOS # service sshd restart ## ubuntu # /etc/init.d/ssh restart
2、通过 SecureCRT生成密钥
1、Tools - Create Public Key
2、Select Key type: RSA
3、对私钥设置口令, 也可以不设置
4、设置密钥长度
5、关键,一定要选择 "OpenSSH Key format" , 为什么呢? 等一下再说,这和多种实现 key 格式不一致有关。
这里选择生成的密钥使用 OpenSSH Key 格式。如果选择默认的格式,上传到服务器的时候需要执行格式转换的工作,需要通过命令行来连接的也需要通过securecrt来转换私钥为openssh格式,这里建议采用openssh key格式!点击完成后会生成两个文件,默认是Identity和Identity.pub,其中Identity为私钥,Identity.pub为公钥。
6、上传 公钥 到远程服务器
通过 sftp, 或者 ftp(ASCII模式)把刚才创建生成的公钥(Identity.pub) 上传到远程服务器, $HOME/.ssh 目录下。如果此用户home目录没有 .ssh 目录,则手动创建。
## 如果没有 .ssh 目录执行 mkdir .ssh 进行创建 # mkdir .ssh # chmod 700 .ssh # cd .ssh # mv Identity.pub authorized_keys # chmod 600 authorized_keys # 如果密钥的格式不是OpenSSH的,需要进行转换 # ssh-keygen –i –f <公钥文件> >> ./.ssh/authorized_keys //转换为公钥为openssh能识别的公钥格式,转换后的文件名为authorized_keys,这是ssh的公钥文件) # ssh-keygen -i -f Identity.pub >> authorized_keys
7、编辑 sshd_config 配置文件
# vi /etc/sshd_config Protocol 2 ServerKeyBits 2048 PermitRootLogin no #禁止root登录而已,与本文无关,加上安全些 #以下三行没什么要改的,把默认的#注释去掉就行了 RSAAuthentication yes PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys PasswordAuthentication no #初次试验的时候最好用yes,否则配置错误的话重启sshd后你就悲剧了 PermitEmptyPasswords no # 在确定你的公钥加入到authorzed_keys后重启sshd服务 # /etc/init.d/sshd restart
8、通过SecureCRT 登录
首先设置登录模式为PublicKey,并选择刚刚创建的公钥文件 Identity.pub。
右键要连接的服务器—会话属性, 在authentication选项中只勾选PublicKey或者将PublicKey选项提到首选,再选中它点击Properties。
指定我们刚创建的私钥。
OK,Over...
通过 Xshell 生成密钥
Xshell是一款Windows下面功能强大的SSH客户端,能够按分类保存N多会话、支持Tab、支持多密钥管理等等,管理比较多的VPS/服务器使用XShell算是比较方便的,而且对于 home/school 是free的,推荐使用。
1、Tools
二、将密钥添加到远程Linux服务器
1、用winscp,将id_rsa.pub文件上传到/root/.ssh/下面(如果没有则创建此目录),并重命名为:authorized_keys(如果是在Linux服务器上生成的密钥直接执行:mv /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys),再执行:chmod 600 /root/.ssh/authorized_keys 修改权限。
2、修改/etc/ssh/sshd_config 文件,将RSAAuthentication 和 PubkeyAuthentication 后面的值都改成yes ,保存。
3、重启sshd服务,Debian/Ubuntu执行/etc/init.d/ssh restart ;CentOS执行:/etc/init.d/sshd restart。
五、增强 ssh 安全性
##SSH服务器监听的选项 #修改监听的端口,可以增加入侵者探测系统是否运行了 sshd守护进程的难度。 Port 42333 #使用SSH V2协议 Protocol 2 #监听的地址为所有地址 #ListenAdderss 0.0.0.0 ListenAdderss 192.168.5.0/24 #禁止DNS反向解析 UseDNS no # 密钥长度 ServerKeyBits 2048 ##用户登录控制选项 #是否允许root用户登录,如果允许用户使用root用户登录,那么黑客们可以针对root用户尝试暴力破解密码,给系统安全带来风险。 PermitRootLogin no #是否允许空密码用户登录,允许使用空密码系统就像不设防的堡垒,任何安全措施都是一句空话。 PermitEmptyPasswords no #登录验证时间(2分钟) LoginGraceTime 2m #最大重试次数 MaxAuthTries 6 #只允许user用户登录,与DenyUsers选项相反 AllowUsers user1 user2 # 禁止指定的 用户或组 DenyUsers apache #注:Allow 和 Deny 可以组合使用,它们的处理顺序是:DenyUsers, AllowUsers, DenyGroups, AllowGroups ##登录验证方式 #关闭密码验证 PasswordAuthentication no #以下三行没什么要改的,把默认的#注释去掉就行了 RSAAuthentication yes #启用秘钥验证 PubkeyAuthentication yes #指定公钥数据库文件 AuthorsizedKeysFile .ssh/authorized_keys
另外,限制登录设置主要是对hosts.allow与hosts.deny就行改动
首先限制所有IP都无法连接,我们顺便将FTP的限制也加入其中。注意要想FTP限制起作用,需要修改配置中的tcp_wrappers=YES。
vi /etc/hosts.deny
sshd:ALL
vsftpd:ALL
设定允许指定的IP地址连接:
vi /etc/hosts.allow # xxx.xxx.xxx.表示网段
sshd:192.168.1.
vsftpd:192.168.1.