SSH的一些知识总结

SSH的一些知识总结

SSH(Secure Shell)是用于加密两台计算机之间的通信,并支持各种身份验证机制的网络协议。

当用户登录远程服务器时,需要将密码传给服务器,如果这个过程是明文通信,则存在被窃听和篡改的风险,SSH正是为了解决此问题而推出的,加密计算机之间的通信,并对操作者进行认证和授权。

OpenSSH现是最流行的SSH实现,几乎所有的Linux发行版都自带OpenSSH,其软件架构是服务器-客户端模式(Server-Client)模式。客户端在OpenSSH中的实现为ssh,服务器在OpenSSH中的实现为sshd。OpenSSH还提供一些辅助工具软件(ssh-keygen、ssh-agent)和专门的客户端工具(scp和sftp)。

SSH客户端

OpenSSH的客户端是二进制程序ssh,在macOS系统中的/usr/bin/ssh

ssh登录服务器命令如下:

1
2
3
4
5
6
7
8
# hostname是主机名,可以是域名、IP地址或者局域网内部主机名
ssh hostname
# 不指定用户名的情况下,默认使用客户端当前用户名作为登录远程服务器的用户名
# 可以用如下两种方式指定用户名
ssh user@hostname
ssh -l username host
# ssh默认连接服务器的22端口,-p可指定端口
ssh -p 8821 foo.com

ssh连接服务器后,会验证远程服务器是否为陌生地址,这是由于ssh会将所有连接过的服务器公钥指纹(公钥哈希值)存储到本机的~/.ssh/known_hosts文件中,连接时会判断主机的指纹是否在此文件中。验证结束后,ssh就会要求用户输入登录账户的密码,密码验证正确后就能登录到远程服务器的Shell了。

ssh命令行存在多个配置项,用于修改它的默认行为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 指定加密算法
ssh -c 3des server.example.com
# 压缩数据传输
ssh -C server.example.com
# 将指定端口收到的请求都转发到服务器
ssh -D 1080 server.example.com
# 指定配置文件
ssh -F /usr/local/ssh/other_config
# 指定私钥
ssh -i my-key server.example.com
# 指定登录用户名
ssh -l zhouhe server.example.com
# 发向本地的9999端口请求都会经过remoteServer转发给targetServer的80端口
ssh -L 9999:targetServer:80 user@remoteServer
# 指定校验数据完整性的算法
ssh -m hmac-sha1,hmac-md5 server.example.com
# 指定ssh连接的服务器端口
ssh -p 2020 server.example.com

在macOS中,SSH客户端的全局配置文件是/etc/ssh/ssh_config,用户个人配置文件是~/.ssh/config,优先级高于全局配置文件。

SSH密钥登录

登录步骤:

  1. 客户端通过ssh-keygen生成自己的公私钥;
  2. 客户端将公钥传到服务器指定位置;
  3. 客户端向服务器发起SSH登录请求;
  4. 服务器收到来自客户端的SSH登录请求后,发送一些随机数给用户,要求证明自己的身份;
  5. 客户端收到来自服务器的数据,使用私钥加密后,发送给服务器;
  6. 服务器将来自客户端的加密数据用对应公钥解密,与原数据对比确认准确后,允许用户登录。

在客户发起SSH登录请求前,用户使用OpenSSH提供的工具ssh-keygen来生成公私钥,用法如下:

1
2
3
# 使用rsa算法生成公私钥,私钥保存在~/.ssh/id_rsa中,公钥保存在~/.ssh/id_rsa.pub中
# zhouhe@zhouhegu.com是公钥的注释信息,用来表明是用户(zhouhe)和服务器(zhouhegu.com)对应的公钥
ssh-keygen -t rsa zhouhe@zhouhegu.com
1
2
3
4
# 检查某个服务器是否在know_hosts文件中
ssh-keygen -F server.example.com
# 将服务器从know_hosts文件中移除
ssh-keygen -R server.example.com

密钥生成后,需要上传到服务器,才能用公钥登录。

OpenSSH规定,用户公钥保存在服务器的~/.ssh/authorized_keys文件,可以选择手动和ssh-copy-id命令自动上传两种方式。

1
2
3
4
5
6
7
# 手动上传
cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
# 权限设置为只有文件所有者才能写
chmod 644 ~/.ssh/authorized_keys

# 使用ssh-copy-id命令上传
ssh-copy-id -i key_file user@host

公钥上传到服务器后,用户下次登录时,OpenSSH就会自动采用密钥登录,不再提示输入密码。注意:如果私钥设置了密码,需要使用密码解开私钥。

如果每次都要输入私钥密码,会让人感到麻烦,ssh-agent命令就是为了解决此问题设计。

1
2
3
4
5
6
7
8
9
10
11
12
# 新建对话
ssh-agent zsh
# 当前对话启用ssh-agent
eval 'ssh-agent'
# 添加默认私钥
ssh-add
# 添加指定私钥
ssh-add my-otehr-key-file
# 登录服务器
ssh remoteHost
# 退出ssh-agent,或者Ctrl+D
ssh-agent -k

SSH服务器

OpenSSH的服务器软件是sshd,可通过sshd命令启动,若提示”sshd re-exec requires execution with an absolute path”,则需要用绝对路径/usr/sbin/sshd启动,接着若提示”sshd: no hotkeys available - exiting”,则需要使用ssh-keygen生成密钥:

1
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key

之后通过命令chmod 600修改生成密钥文件的权限即可。

在macOS上,可通过如下命令启动和停止sshd服务

1
2
3
4
5
6
7
8
# 启动sshd服务
~ sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist
# 查看sshd服务是否启动
~ sudo launchctl list | grep ssh
- 0 com.openssh.sshd
# 停止sshd服务
~ sudo launchctl unload -w /System/Library/LaunchDaemons/ssh.plist
~ sudo launchctl list | grep ssh

sshd的相关配置文件都在/etc/ssh目录下,主要的配置文件是sshd_config,以及生成的密钥文件:

  • /etc/ssh/sshd_config: 配置文件
  • /etc/ssh/ssh_host_key: 用于SSH1协议版本的RSA私钥
  • /etc/ssh/ssh_host_key.pub: 用于SSH1协议版本的RSA公钥
  • /etc/ssh/ssh_host_rsa_key: 用于SSH2协议版本的RSA私钥
  • /etc/ssh/ssh_host_rsa_key.pub: 用于SSH2协议版本的RSA公钥

sshd启动时会自动读取默认的配置文件,可通过-f参数指定配置文件:

1
sshd -f /usr/local/ssh/my_config

SSH端口转发

SSH除了登录服务器外,还能作为加密通信媒介,当两台服务器之间的通信加密跳板,使得原本不加密的通信变成加密通信,此功能就是端口转发(port forwading),又称SSH隧道。通过端口转发来访问Telnet、FTP等明文服务,数据传输就都会加密。端口转发分为动态转发,本地转发和远程转发三种方式。

动态转发指的是本机与SSH服务器建立一个加密连接,本机针对某个端口的通信都通过此加密连接转发。

1
# -D表示动态转发,local-port是本地端口,tunnel-host是SSH服务器,# -N表示此SSH连接只进行端口转发,不登录远程Shell,不执行命令,只充当隧道ssh -D local-port tunnel-host -N

采用动态转发访问外部网站时,需要把HTTP请求转成SOCKS5协议,才能把本地端口的请求转发出去,例如

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

如果经常使用动态转发,可以在ssh个人配置文件~/.ssh/config中添加

1
DynamicForward tunnel-host:local-port

本地转发指的是SSH服务器作为跳板机,建立本地计算机与特定目标网站之间的加密连接,所有发向本地端口的请求都会转发到SSH跳板机(tunnel-host),然后SSH跳板机作为中介,将收到的请求发到目标服务器(target-host)的目标端口(target-port)。

1
ssh -L local-port:target-host:target-port tunnel-hostssh -L 2121:www.example.com:80 tunnel-host -N

然后访问本机的2121端口,就是访问www.example.com的80端口

1
curl http://localhost:2121

如果经常使用本地转发,可以将设置写入ssh个人配置文件~/.ssh/config

1
Host test.example.comLocalForward client-IP:client-port server-IP:server-port

远程转发指的是在远程SSH服务器建立转发的规则,与本地转发刚好相反,本地转发是通过本地计算机访问远程计算机,而远程转发则是通过远程计算机访问本地计算机。

1
ssh -R remote-port:target-host:target-port -N remotehost

如果经常执行远程转发,可以将设置写入ssh个人配置文件~/.ssh/config

1
Host remote-forward	HostName test.example.com	RemoteForward remote-port target-host:target-port

scp命令

scp(secure copy)是SSH提供的一个客户端程序,用于在两台主机之间加密传送文件(复制文件),相当于是SSH协议下执行cp命令,scp传输数据时,文件和密码都加密。

1
# 将服务器user@host用户目录下的foo.txt复制到客户端当前目录下的bar.txt文件scp user@host:foo.txt bar.txt# 将客户端bar.txt文件复制到服务器用户目录下foo.txtscp bar.txt user@host:foo.txt# 将服务器host1中的file.txt文件复制到服务器host2中files目录下scp user1@host1:/files/file.txt user2@host2:/files

sftp命令

sftp(secure ftp)是SSH提供的一个客户端程序,用于来安全访问FTP服务,相当于SSH协议下的FTP协议。

1
# 连接ftp服务器sftp username@hostname# 本地文件传输到远程主机put localfile [remotefile]# 远程文件传输到本地get remotefile [localfile]# 退出sftpquit or exit or bye

参考

网道/SSH教程