SSH详解

ssh的软件架构是服务器-客户端模式(Server - Client)

在这个架构中,SSH软件分成两个部分:

  • 向服务器发出请求的部分,称为客户端 client,OpenSSH的实现位ssh
  • 接收客户端发出的请求的部分,称为服务器 server, OpenSSH的实现位sshd

OpenSSH还提供一些辅助工具软件(比如ssh-keygen、ssh-agent)和专门的客户端工具(比如scp和ftp)

SSH 客户端

执行远程命令

另一种执行远程命令的方法,是将命令直接写在ssh命令的后面。

$ ssh username@hostname command

采用这种语法执行命令的时候,不会提供互动式的shell环境。

如果需要互动式环境需要添加一个参数-t

ssh命令行配置项

-c : 指定加密算法

-C : 表示压缩数据传输

-D : 指定本机的Socks监听端口,该端口收到的请求,都将转发到远程的SSH主机,又称动态端口转发

ssh -D 1080 server

将本机1080端口收到的请求,都转发到服务器server

-f : 表示SSH连接在后台运行

-F : 参数指定配置文件

-i : 指定私钥

-l : 指定远程登录的账户名

-L : 设置本地端口转发

$ ssh  -L 9999:targetServer:80 user@remoteserver

上面命令中,所有发向本地9999端口的请求,都会经过remoteserver发往 targetServer 的 80 端口,这就相当于直接连上了 targetServer 的 80 端口

-m : 指定校验数据完整性的算法(message authentication code,简称MAC)

-N : 用于端口转发,表示建立的SSH只用于端口转发,不能执行远程命令

-o : 指定一个配置命令

-p : 指定ssh客户端连接的服务器端口

-q : 安静模式(quiet),不向用户输出任何警告信息

-R : 指定远程端口转发

$ ssh -R 9999:targetServer:902 local

上面命令需在跳板服务器执行,指定本地计算机local监听自己的 9999 端口,所有发向这个端口的请求,都会转向 targetServer 的 902 端口。

-t : 参数在ssh直接运行远端命令时,提供一个互动式Shell

-v : 参数显示详细信息,v可以重复多次,表示信息的详细程度

-V : 输出ssh客户端的版本

客户端配置文件

个人配置文件的优先级要高于全局配置文件

全局配置文件:/etc/ssh/ssh_config

个人配置文件:~/.ssh/config

功能

按照不同的服务器,列出各自的连接参数,从而不必每一次登录都输入重复的参数

Host *
     Port 2222

Host remoteserver
     HostName remote.example.com
     User neo
     Port 2112

Hsot * 代表对所有的主机都生效,缩进不是必须的

remoteserver只是一个别名,可以直接使用ssh remoteserver命令,就会套用config里面的参数进行连接

SSH密钥登录

密钥(key)是一个非常大的数字,通过加密算法得到。对称加密只需要一个密钥,非对称加密需要两个密钥成对使用,分为公钥和私钥。

如果数据使用公钥加密,那么只有使用对应的私钥才能解密,其他密钥都不行;反过来,如果使用私钥加密(一般称之为签名)也只能使用对应的公钥解密。

验证步骤

预备步骤,客户端通过ssh-keygen生成自己的公钥和私钥。

ssh-keygen -t dsa

-t参数用来指定密钥的加密算法,一般会选择dsa算法或者rsa算法,此参数必须要指定

第一步,手动将客户端的公钥放入远程服务器的指定位置。

第二步,客户端向服务器发起 SSH 登录的请求。

第三步,服务器收到用户 SSH 登录的请求,发送一些随机数据给用户,要求用户证明自己的身份。

第四步,客户端收到服务器发来的数据,使用私钥对数据进行签名,然后再发还给服务器。

第五步,服务器收到客户端发来的加密签名后,使用对应的公钥解密,然后跟原始数据比较。如果一致,就允许用户登录。

生成密钥以后,建议修改它们的权限,防止其他人读取。

$ chmod 600 ~/.ssh/id_rsa
$ chmod 600 ~/.ssh/id_rsa.pub

手动上传公钥

OpenSSH规定,用户公钥保存在服务器的~./ssh/authorized_keys文件。要以哪个用户的身份登录到服务器,密钥就必须保存在该用户主目录的~/.ssh/authorized_keys文件。只要把公钥添加到这个文件之中,就相当于公钥上传到服务器了。每个公钥占据一行。如果该文件不存在,可以手动创建。

用户可以手动编辑该文件,把公钥粘贴进去,也可以在本机计算机上,执行下面的命令。

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

注意,authorized_keys文件的权限要设为644,即只有文件所有者才能写。如果权限设置不对,SSH 服务器可能会拒绝读取该文件。

ssh-copy-id 自动上传公钥

OpenSSH 自带一个ssh-copy-id命令,可以自动将公钥拷贝到远程服务器的~/.ssh/authorized_keys文件。如果~/.ssh/authorized_keys文件不存在,ssh-copy-id命令会自动创建该文件。

用户在本地计算机执行下面的命令,就可以把本地的公钥拷贝到服务器。

$ ssh-copy-id -i key_file user@hosts

上面命令中,-i参数用来指定公钥文件,user是所要登录的账户名,host是服务器地址。如果省略用户名,默认为当前的本机用户名。执行完该命令,公钥就会拷贝到服务器。

注意,公钥文件可以不指定路径和.pub后缀名,ssh-copy-id会自动在~/.ssh目录里面寻找。

$ ssh-copy-id -i id_rsa user@host

端口转发

SSH除了可以登录服务器,还可以作为加密通信的中介,充当两台服务器之间的通信加密跳板,使得原本不加密的通信变成加密通信。这个功能称为端口转发(port forwarding),又称SSH隧道(tunnel)。

主要有两个作用:

  1. 将不加密数据放在SSH安全连接里面传输,增加不安全网络服务的安全性。
  2. 作为数据通信的加密跳板,绕过网络防火墙

三种使用方法:

  1. 动态转发
  2. 本地转发
  3. 远程转发

动态转发

动态转发指的是,本机与SSH服务器之间创建一个加密连接,然后本机内部针对某个端口的通信,都通过这个加密连接转发。对于本地转发远程转发,都存在两个一一对应的端口,分别位于SSH的客户端和服务端,而动态转发只是绑定了一个本地端口,而目标地址:目标端口都是不固定的。目标地址:目标端口是由发起的请求决定的。

使用场景

  1. 访问所有外部网站,都通过SSH转发。(可做为简易VPN)

  2. SSH服务器端运行了多个服务,使用了不同的端口,本地主机需要访问这些服务

为什么需要动态端口转发

  1. 由于防火墙的限制,本地主机并不能直接访问远程主机上的服务
  2. 存在多个服务的话,为每个端口分别创建本地端口转发非常麻烦
ssh -D localhost:port tunnel-host
# example
ssh -D localhost:2121 root@112.3.42.245

在本地发起的请求,需要由Socket代理(Socket Proxy))转发到SSH绑定的2121端口。

以浏览器的proxy代理为例,浏览器发起的请求都会转发到2121端口,然后通过SSH转发到真正的请求地址。

20210803113613

若Node.js服务运行在远程云主机上,则在浏览器中访问localhost:3000即可以访问。如果主机B1能够访问外网的话,则可以访外网……

除了使用浏览器外,也可以通过命令行访问

$ curl -x socks5://localhost:2121 http://www.example.com

本地转发

一般来讲,云主机的防火墙默认只打开了22端口,如果需要访问3000端口的话,需要修改防火墙。为了保证安全,防火墙需要配置允许访问的IP地址。但是,本地公网IP通常是网络提供商动态分配的,是不断变化的。这样的话,防火墙配置需要经常修改,就会很麻烦。

本地转发就是将发送到本地端口的请求,转发到目标端口。这样就可以通过访问本地端口,来访问目标端口的服务。

ssh -L 本机地址:本地端口:目标地址:目标端口

通过本地端口转发,可以将发送到本地主机端口的请求,转发到远程主机端口上。

# 在本地主机登陆远程主机,并进行本地端口转发
ssh -L localhost:2000:local:3000 root@103.59.22.17

这样,在本地主机A1上可以通过访问http://localhost:2000来访问远程云主机3000端口上的服务。

实际上,-L选项中的本地网卡地址是可以省略的,这时表示2000端口绑定了本地主机的所有网卡:

# 在本地主机A1登陆远程云主机B1,并进行本地端口转发。2000端口绑定本地所有网卡
ssh -L 2000:localhost:3000 root@103.59.22.17

若本地主机A2能够访问A1,则A2也可以通过A1访问远程远程云主机B1上的Node.js服务。

另外,-L选项中的目标地址也可以是其他主机的地址。假设远程云主机B2的局域网IP地址为192.168.59.100,则可以这样进行端口转发:

# 在本地主机A1登陆远程云主机B1,并进行本地端口转发。请求被转发到远程云主机B2上
ssh -L 2000:192.168.59.100:3000 root@103.59.22.17

远程转发

应用场景:本地主机运行了一个服务,端口为3000,而本地主机没有一个固定的公网ip地址,远程主机需要访问这个服务

如果本地主机有一个独立公网ip,那么我们可以通过本地转发来访问本地主机上的服务。

但是大部分的时候本地主机都是在局域网内,与很多设备共享一个ip。

因此遇到这样的情况,我们需要远程转发来解决。

定义

远程转发就是将发送到远程端口的请求,转发到目标端口。这样就可以通过访问远程端口,来访问目标端口的服务。

-R 远程网卡地址:远程端口:目标地址:目标端口

通过远程转发,可以将发送到远程云主机2000端口的请求,转发到本地主机的3000端口。

# 在本地主机A1登陆远程主机B1,并进行远程端口转发
ssh -R localhost:2000:local:3000 root@103.59.22.17

这样,在远程主机A1可以通过访问http://localhost:2000来访问本地主机的服务。

同理,远程网卡地址可以省略,目标地址也可以是其他主机地址。假设本地主机A2的局域网IP地址为192.168.0.100

# 在本地主机A1登陆远程云主机B1,并进行远程端口转发
ssh -R 2000:192.168.0.100:3000 root@103.59.22.17

参考文章

1.https://wangdoc.com/ssh/port-forwarding.html
2.https://blog.fundebug.com/2017/04/24/ssh-port-forwarding/

posted @ 2021-08-03 17:07  Xi-iX  阅读(1892)  评论(0编辑  收藏  举报