当前位置:首页 > 技术文章 > 正文内容

Centos7学习笔记(十四)- SSH部分

ivker_lee5年前 (2020-09-05)技术文章385

1、数字签名

了解ssh之前,先了解什么是数字签名?

http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html

http://www.youdzone.com/signature.html

参看这2篇文章,通俗易懂的解释了什么是数字签名。简单的讲,就是有一个CA中心,它可以颁发“数字证书”,这个证书,可以证明其后的公钥真伪性,以便客户端正确识别。

2、SSH基本原理与运用(一)

以下部分,抄录于“阮一峰”博客,链接:https://www.ruanyifeng.com/blog/2011/12/ssh_remote_login.html

a)、基本用法

SSH主要用于远程登录。假定你要以用户名user,登录远程主机host,只要一条简单命令就可以了。

  $ ssh user@host

如果本地用户名与远程用户名一致,登录时可以省略用户名。

 $ ssh host

SSH的默认端口是22,也就是说,你的登录请求会送进远程主机的22端口。使用p参数,可以修改这个端口。

 $ ssh -p 2222 user@host

上面这条命令表示,ssh直接连接远程主机的2222端口。


b)、中间人攻击


SSH之所以能够保证安全,原因在于它采用了公钥加密。

整个过程是这样的:(1)远程主机收到用户的登录请求,把自己的公钥发给用户。(2)用户使用这个公钥,将登录密码加密后,发送回来。(3)远程主机用自己的私钥,解密登录密码,如果密码正确,就同意用户登录。

这个过程本身是安全的,但是实施的时候存在一个风险:如果有人截获了登录请求,然后冒充远程主机,将伪造的公钥发给用户,那么用户很难辨别真伪。因为不像https协议,SSH协议的公钥是没有证书中心(CA)公证的,也就是说,都是自己签发的。


以下图说明SSH认证中间过程:


对上图的具体解读:

初始状态:topgun终端要登录Server服务器,发起连接请求ssh work@server.com

  1. 服务端运行有ssh服务,并持续监听22号端口,因此可以生成一对公钥和私钥;此时将公钥返回给客户端

  2. 客户端使用公钥,对登录密码进行加密,(如服务器work用户密码为xxx),生成公钥加密字符串

  3. 客户端将公钥加密字符串发送给服务端

  4. 服务端使用私钥,解密公钥加密字符串,得到原始密码

  5. 校验密码是否合法(此为本机work密码)

  6. 返回登录结果给客户端:成功登录或密码错误

在非对称加密中,由于只有公钥会被传输,而私钥是服务端本地保存,因此即便公钥被监听,也无法拿到原始密码,从而登录服务器。


可以设想,如果攻击者插在用户与远程主机之间(比如在公共的wifi区域),用伪造的公钥,获取用户的登录密码。再用这个密码登录远程主机,那么SSH的安全机制就荡然无存了。这种风险就是著名的"中间人攻击"(Man-in-the-middle attack)。

中间人攻击原理图

SSH协议是如何应对的呢?

(说起来其实很简单,ssh让用户自行核实远程主机(server)提供的真实性安全性,具体来说,就是通过获取远程主机明文贴示出的公钥,并对其进行hash计算后,得到128位指纹值,然后本地人工验证,即下面“口令登录”的内容)


c)、口令登录

如果你是第一次登录对方主机,系统会出现下面的提示:  

$ ssh user@host
  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.

然后,会要求输入密码。 

Password: (enter password)

如果密码正确,就可以登录了。

当远程主机的公钥被接受以后,它就会被保存在文件$HOME/.ssh/known_hosts之中。下次再连接这台主机,系统就会认出它的公钥已经保存在本地了,从而跳过警告部分,直接提示输入密码。

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


d)、公钥登录(免密登录)


使用密码登录,每次都必须输入密码,非常麻烦。好在SSH还提供了公钥登录,可以省去输入密码的步骤。

所谓"公钥登录",原理很简单,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。

这种方法要求用户必须提供自己的公钥。如果没有现成的,可以直接用ssh-keygen生成一个: 

$ ssh-keygen

ssh-keygen常用参数如下:

  • -t: 指定生成密钥类型(rsa、dsa)。默认为rsa

  • -f: 指定存放私钥的文件,公钥文件名为私钥文件名加.pub后缀。默认为id_rsa

  • -P: 指定passphrase(私钥的密码),用于确保私钥的安全。默认为空

  • -C: 备注。默认为user@hostname


运行上面的命令以后,系统会出现一系列提示,可以一路回车。其中有一个问题是,要不要对私钥设置口令(passphrase),如果担心私钥的安全,这里可以设置一个。

运行结束以后,在$HOME/.ssh/目录下,会新生成两个文件:id_rsa.pub和id_rsa。前者是你的公钥,后者是你的私钥。

这时再输入下面的命令,将公钥传送到远程主机host上面:

 $ ssh-copy-id user@host

ssh-copy-id命令就几个参数,

-f不检查远端主机是否存在公钥文件,可能导致远端主机有多份公钥文件的拷贝。

-n不是安装公钥文件到远程主机,仅仅是把文件内容打印看一下。

-i指定公钥文件名,若不指定,则用默认名。

-p指定ssh端口

-o指定ssh参数选项

需要说明的是,如果是为一个之前从未ssh登录过的远端主机做次免密登录,那么上面的口令登录过程,还是免不了要来一遍的,类似下面过程(当然,也可以用-o StrictHostKeyChecking=no的方式来免除那个输入yes的过程)。

(若想完全做到非交互式执行命令呢?那么需要安装sshpass软件,用“sshpass -p密码  ssh-copy-id -f -i ~/.ssh/abc.pub  "-o StrictHostKeyChecking=no" -p 11223 root@192.168.1.30” )

[root@c7study ~]# ssh-copy-id -i abc.pub -p 11223 root@192.168.1.30
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "abc.pub"
The authenticity of host '192.168.1.30:11223 ([192.168.1.30]:11223)' can't be established.
ECDSA key fingerprint is SHA256:+J2vwsLe2Jp5lI/aQLm9kLDRSaHrKXsbSg1a/jvTKGc.
ECDSA key fingerprint is MD5:ab:13:a3:6e:52:3a:7b:42:b0:04:3e:a6:ce:f8:b1:fd.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@www.hcrbbs.top's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh -p '11223' 'root@192.168.1.30'"
and check to make sure that only the key(s) you wanted were added.


(补充说明一下,执行以上命令,其实就是将本地生成的公钥id_rsa.pub内容,完全复制到远端主机user用户.ssh/目录下的authorized_keys文件中,如果.ssh目录和该文件都没有,则先创建再复制)

(么完成这一步,正常情况下,远端主机user用户.ssh/目录下应仅有authorized_keys文件。在etc/ssh/下,ssh_host_*_key文件和ssh_host_*_key.pub文件,分别对应各类算法下,自身的公钥文件和私钥文件)

好了,从此你再登录,就不需要输入密码了。

如果还是不行,就打开远程主机的/etc/ssh/sshd_config这个文件,检查下面几行前面"#"注释是否取掉。 

RSAAuthentication yes
  PubkeyAuthentication yes
  AuthorizedKeysFile .ssh/authorized_keys

然后,重启远程主机的ssh服务。 

// ubuntu系统
  service ssh restart
  // debian系统
  /etc/init.d/ssh restart

PS:特别要注意,这里有一个巨坑——如果在ssh-keygen时,用-f参数指定了私钥文件名(比如不叫默认的id_rsa,改为manger_rsa之类。包括指定了私钥文件名的存放位置,比如这样:"-f /home/study/manger_rsa"),那么,一定要在“~/.ssh/”下生成“config”文件,并在文件中,指定私钥文件名的位置(就如下面要讲的“所Server免密登录配置”中的config文件配置一样)。原因呢,就因为在执行ssh登录的时候,如果没有config配置文件,那么默认引用的私钥就是“~/.ssh/id_rsa”,但这个文件因为-f参数,并不存在,所以秘钥认证过程,就会因为找不到私钥文件,认证不通过,从而又变成了password认证。

$vim ~/.ssh/config

Host 172.16.1.7
User study
IdentityFile ~/.ssh/manager_rsa

网上有一篇文章——https://www.cnblogs.com/li-mzx/p/13140061.html,详细讲述了,免密配置后还出现密码认证的调试解决过程,非常有参考意义。

其中,主要的是让服务器端,用/bin/sbin/sshd -d的方式,将ssh服务以守护进程的方式运行,方便直接调试显示ssh认证过程中的错误。客户端呢,ssh增加-v参数,显示认证过程的详细信息,便于查看分析问题。


e)多Server免密登录配置

首先说明一下免密登录配置后,本地用户.ssh/目录下所应有的文件

id_rsa    // 私钥文件,执行ssh-keygen生成,未指定私钥文件名时,默认的文件名 
id_rsa.pub    // 公钥文件,执行ssh-keygen生成
known_hosts    // 确认过公钥指纹的可信服务器列表的文件,这个文件仅在未实行免密登录前,就成功认证登录远端Server后产生
config    // 默认无该文件,可手工创建产生,可用户指定不同域名使用哪个密钥的配置文件

(如果本地主机,也被当做ssh服务端并做免密ssh远程访问过,那么,也会有“authorized_keys” 文件)

我们的服务器会有很多的用户,如果所有的用户都用同一份密钥,可能就没办法划分权限或者区分用户,如多个用户提交git就需要按照用户名来生成密钥,用于区分用户。同时你可能也希望针对不同的服务器使用不同的密钥对,因此需要config配置文件来配置针对不同服务器的配置:

$vim ~/.ssh/config
Host a.baidu.com                     《=============   目标主机(服务端)名称,可以是域名,可以是IP地址,可以是netbios名称 
User work                            《=============   目标主机的ssh登录用户名
Port 52113                            《=============   目标主机的ssh登录端口
IdentityFile ~/.ssh/id_rsa           《=============   客户端所需要引用的私钥文件,需要写绝对路径

Host b.baidu.com
User user
IdentityFile ~/.ssh/user

这样在连接不同的服务器时,就会使用不同的密钥文件来登录。

在客户端生成密钥对之后,将公钥追加到服务器的authorized_keys文件中即可。

(这里,需要注意,config文件权限必须是600

其实,不光是config文件的权限,整个需要注意服务端和客户端“”~”目录的权限必须是700,“.ssh”目录的权限必须是600

贴一个实际在用的config文件写法:

HOST    172.16.1.*
        User study
        Port 52113
        IdentityFile ~/.ssh/m01_61
HOST    www.hcrbbs.top
        User root
        Port 56319
        IdentityFile ~/.ssh/www_hcrbbs


免密登录的原理图,用下图表达:

具体解释:

  1. 在客户端使用ssh-keygen生成一对密钥:公钥+私钥

  2. 将客户端公钥追加到服务端的authorized_key文件中,完成公钥认证操作

  3. 认证完成后,客户端向服务端发起登录请求,并传递公钥到服务端

  4. 服务端检索authorized_key文件,确认该公钥是否存在

  5. 如果存在该公钥,则生成随机数R,并用公钥来进行加密,生成公钥加密字符串pubKey(R)

  6. 将公钥加密字符串传递给客户端

  7. 客户端使用私钥解密公钥加密字符串,得到R

  8. 服务端和客户端通信时会产生一个会话ID(sessionKey),用MD5R和SessionKey进行加密,生成摘要(即MD5加密字符串)

  9. 客户端将生成的MD5加密字符串传给服务端

  10. 服务端同样生成MD5(R,SessionKey)加密字符串

  11. 如果客户端传来的加密字符串等于服务端自身生成的加密字符串,则认证成功

  12. 此时不用输入密码,即完成建连,可以开始远程执行shell命令了


f)、authorized_keys文件


远程主机将用户的公钥,保存在登录后的用户主目录的$HOME/.ssh/authorized_keys文件中。公钥就是一段字符串,只要把它追加在authorized_keys文件的末尾就行了。

这里不使用上面的ssh-copy-id命令,改用下面的命令,解释公钥的保存过程:  

$ ssh user@host 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub

这条命令由多个语句组成,依次分解开来看:(1)"$ ssh user@host",表示登录远程主机;(2)单引号中的mkdir .ssh && cat >> .ssh/authorized_keys,表示登录后在远程shell上执行的命令:(3)"$ mkdir -p .ssh"的作用是,如果用户主目录中的.ssh目录不存在,就创建一个;(4)'cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub的作用是,将本地的公钥文件~/.ssh/id_rsa.pub,重定向追加到远程文件authorized_keys的末尾。

写入authorized_keys文件后,公钥登录的设置就完成了。


3、SSH原理与运用(二)

以下部分,抄录于“阮一峰”博客,链接:http://www.ruanyifeng.com/blog/2011/12/ssh_port_forwarding.html

g)、远程操作


SSH不仅可以用于远程主机登录,还可以直接在远程主机上执行操作。

上一节的操作,就是一个例子:  

$ ssh user@host 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub

单引号中间的部分,表示在远程主机上执行的操作;后面的输入重定向,表示数据通过SSH传向远程主机。

这就是说,SSH可以在用户和远程主机之间,建立命令和数据的传输通道,因此很多事情都可以通过SSH来完成。

下面看几个例子。

【例1】

将$HOME/src/目录下面的所有文件,复制到远程主机的$HOME/src/目录。  

$ cd && tar czv src | ssh user@host 'tar xz'

【例2】

将远程主机$HOME/src/目录下面的所有文件,复制到用户的当前目录。

 $ ssh user@host 'tar cz src' | tar xzv

【例3】

查看远程主机是否运行进程httpd。

 $ ssh user@host 'ps ax | grep [h]ttpd'


h)、绑定本地端口


既然SSH可以传送数据,那么我们可以让那些不加密的网络连接,全部改走SSH连接,从而提高安全性。


假定我们要让8080端口的数据,都通过SSH传向远程主机,命令就这样写:  

$ ssh -D 8080 user@host

SSH会建立一个socket,去监听本地的8080端口。一旦有数据传向那个端口,就自动把它转移到SSH连接上面,发往远程主机。可以想象,如果8080端口原来是一个不加密端口,现在将变成一个加密端口。


i)、本地端口转发

有时,绑定本地端口还不够,还必须指定数据传送的目标主机,从而形成点对点的"端口转发"。为了区别后文的"远程端口转发",我们把这种情况称为"本地端口转发"(Local forwarding)。

假定host1是本地主机,host2是远程主机。由于种种原因,这两台主机之间无法连通。但是,另外还有一台host3,可以同时连通前面两台主机。因此,很自然的想法就是,通过host3,将host1连上host2。

我们在host1执行下面的命令:

 $ ssh -L 2121:host2:21 host3

命令中的L参数一共接受三个值,分别是"本地端口:目标主机:目标主机端口",它们之间用冒号分隔。这条命令的意思,就是指定SSH绑定本地端口2121,然后指定host3将所有的数据,转发到目标主机host2的21端口(假定host2运行FTP,默认端口为21)。

这样一来,我们只要连接host1的2121端口,就等于连上了host2的21端口。

 $ ftp localhost:2121

"本地端口转发"使得host1和host3之间仿佛形成一个数据传输的秘密隧道,因此又被称为"SSH隧道"。


下面是一个比较有趣的例子。

 $ ssh -L 5900:localhost:5900 host3

它表示将本机的5900端口绑定host3的5900端口(这里的localhost指的是host3,因为目标主机是相对host3而言的)。

另一个例子是通过host3的端口转发,ssh登录host2。

 $ ssh -L 9001:host2:22 host3

这时,只要ssh登录本机的9001端口,就相当于登录host2了。 

 $ ssh -p 9001 localhost

上面的-p参数表示指定登录端口。


j)、远程端口转发


既然"本地端口转发"是指绑定本地端口的转发,那么"远程端口转发"(remote forwarding)当然是指绑定远程端口的转发。

还是接着看上面那个例子,host1与host2之间无法连通,必须借助host3转发。但是,特殊情况出现了,host3是一台内网机器,它可以连接外网的host1,但是反过来就不行,外网的host1连不上内网的host3。这时,"本地端口转发"就不能用了,怎么办?

解决办法是,既然host3可以连host1,那么就从host3上建立与host1的SSH连接,然后在host1上使用这条连接就可以了。

我们在host3执行下面的命令:

 $ ssh -R 2121:host2:21 host1

R参数也是接受三个值,分别是"远程主机端口:目标主机:目标主机端口"。这条命令的意思,就是让host1监听它自己的2121端口,然后将所有数据经由host3,转发到host2的21端口。由于对于host3来说,host1是远程主机,所以这种情况就被称为"远程端口绑定"。

绑定之后,我们在host1就可以连接host2了: 

 $ ftp localhost:2121

这里必须指出,"远程端口转发"的前提条件是,host1和host3两台主机都有sshD和ssh客户端。


k)、SSH的其他参数


SSH还有一些别的参数,也值得介绍。

N参数,表示只连接远程主机,不打开远程shell;T参数,表示不为这个连接分配TTY。这个两个参数可以放在一起用,代表这个SSH连接只用来传数据,不执行远程操作。 

$ ssh -NT -D 8080 host

f参数,表示SSH连接成功后,转入后台运行。这样一来,你就可以在不中断SSH连接的情况下,在本地shell中执行其他操作。

$ ssh -f -D 8080 host

要关闭这个后台连接,就只有用kill命令去杀掉进程。


4、scp命令

scp作为ssh的一个附属命令(属于openssh-clients软件),也有推、拉模式,跟rsync相同,具体用法:

推:

scp -P 端口  -rp  本地源文件或目录    用户名@目标主机:/目标目录

拉:

scp -P 端口  -rp  用户名@远端主机:/远端目录   本地目录或文件

具体详见:“Centos7学习笔记(八)-基础命令(三)”中关于scp命令的解释。


5、sftp命令

参数:-oPort————指定使用的端口

sftp登录后的交互命令:

image.png



分享给朋友:

相关文章

 Centos7学习笔记(十六)- 正则表达式高级部分

Centos7学习笔记(十六)- 正则表达式高级部分

1、正则表达式工作流程取得正则字符串并检查正则语法。编译:将正则字符串编译成真正的正则表达式。启动正则引擎开始匹配正则引擎:逐个字符扫描字符串并与编译后的正则表达式的各个元素进行匹配。何为正则元素呢?纯字符组合,比如“abc123”,那么每一个字符都是一个正则元素[a-z]这样的样式,那么视中括号[]为一个整体作为正则元素,中括号内的内容是限定的匹配范围字符匹配的反斜线序列也是一种正则元素字符.是一个独立的正则元素,它除了不能匹配\n,其他任意字符都能匹配所有的*、?、{m}、{m,}、{m,n...

Centos7学习笔记(二十一)- nginx的rewrite

Centos7学习笔记(二十一)- nginx的rewrite

一、什么是rewriterewirte就是实现Url地址重写,以及重定向,就是把传入的web请求重定向到其他URL的过程。二、rewrite的使用场景a、url地址的跳转。比如访问www.example.com/test,重定向到test.example.com网址。b、协议的跳转,主要的就是实现http协议跳转到https页面去。c、实现网站的伪静态。伪静态就是将网站动态页面的诸多参数,显示为一种静态页面的方式,以便于搜索引擎记录,减少URL地址暴露过多参数,提高安全性。d、通过上述伪静态,产...

Centos7学习笔记(五)-tmpfs和xfs

Centos7学习笔记(五)-tmpfs和xfs

介绍/dev/shm/是一个使用就是tmpfs文件系统的设备,其实就是一个特殊的文件系统。redhat中默认大小为物理内存的一半,使用时不用mkfs格式化。tmpfs是Linux/Unix系统上的一种基于内存的虚拟文件系统。tmpfs可以使用您的内存或swap分区来存储文件(即它的存储空间在virtual memory 中, VM由real memory和swap组成)。由此可见,tmpfs主要存储暂存的文件。它有如下2个优势 : 1. 动态文件系统的大小。2. tmpfs 使用VM建的文件系统...

Nginx常用编译模块

Nginx常用编译模块

    因为某些特殊需求,最近在折腾网站支持TLS1.3。因此做一些笔记。    首先,要支持TLS1.3,需要openssl在1.1.0以上版本。需要系统重新编译安装。其次,需要nginx调用新版本openssl,用“nginx -V”命令可以查看调用的openssl版本详情。然后下载对应版本的nginx源码,重新编译nginx。    以下罗列nginx编译常用编译模块:&...

 Centos7学习笔记(十三)- 一个解压用脚本的详细说明

Centos7学习笔记(十三)- 一个解压用脚本的详细说明

#!/bin/bash cd /home/tar #ls出该目录下的文件,并导出所需文件名到file.log文件中 ls *.tar.gz >file.log ls *.tgz >>file.log 2>/dev/null ls *.tar.bz2 >>file.log 2>/dev/null #统计file.log到底有多少文件 num=$(cat&...

记一次大的折腾经历

记一次大的折腾经历

前两天想随手记一下学习exchange2019的知识点,就随手打开了自己博客的后台。先是看见zlog-php程序有版本升级的提示(升级到1.70),也有升级“数据库结构”的提示,没多想,就随手各都点了“升级”。然后新建完文章,保存的时候,出现错误。然后,并发现后台首页,在“清空缓存并重新编译模块”也会出现“操作失败”的错误。在其他更换“主题”,或者重新提交“网站设置”,都会出现上述或者类似错误。一开始完全不知道怎么解决,以为是zblog-php版本随意就升级了,带来的问题,然后去zblog论坛查...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。