远程连接
通常通过SSH(Secure Shell)协议与远程服务器进行加密通信。SSH是一种C/S模式的应用层协议,远程服务器运行SSH服务端,个人电脑上使用SSH客户端去连接服务器上的SHH服务端,当然也可以在一台服务器上使用SSH客户端连接另一台服务器的SSH服务端。
有许多常用操作是基于SSH协议的,例如使用ssh命令进行SSH登录,通过SCP和SFTP传输文件。注意,使用ssh命令登录远程服务器使用的是ssh应用程序,和SSH协议是两种层面的东西,只是这个应用程序内部使用了SSH协议。后面用大写SSH表示协议,小写ssh表示应用程序。
SSH通信过程
SSH整个通信过程涉及对称加密和非对称加密。
对称加密是指通信双方使用同一个密钥进行加密和解密。
非对称加密是指其中一方提供一个密钥对A和B,用A加密的信息只有用B能解密,用B加密的信息也只有A能解密。持有密钥对的一方将密钥A发送给通信的另一方,双方各自用自己持有的密钥进行信息加密,对方收到加密信息后再用其持有的密钥进行解密。这样双方就实现了信息加密传输。其中可以随意发给对方的密钥A称作公钥,自己持有不可泄露的密钥B称为私钥。
对称加密的加解密速度更快,非对称加密的安全性更高。
SSH通信过程可以分为四个阶段:
- 版本号协商,防止双方的协议不兼容。
- 密钥协商。
- 认证。
- 会话请求和交互。
版本号协商的过程不是很重要,主要作用就是确认双方建立了连接,会话请求和交互就是正式通信内容,可以了解一下密钥协商和认证过程。
密钥协商简略过程:
- 服务端发送自己的公钥给客户端,客户端需要判断是否信任该公钥,因为这个公钥可能是第三方截取了客户端的连接请求后伪造的。该怎么判断呢?没法判断,除了联系服务端管理员。这是整个SSH通信过程中最不安全的一步,所以一般都会让用户判断是否信任(反正软件是不背锅的)。HTTPS采用了另一种方式:由权威机构为域名持有者颁发一个数字签名的CA证书,只要是持有该证书的人就一定是域名的持有者(除非自己泄露了)。SSH协议没有这种权威机构也没法有(大多数服务器都是内网环境不可能让别的结构看到的),所以只能无脑相信这个公钥。一般情况下是没有问题的。
- 客户端生成一个会话密钥,用服务端公钥加密后发送给服务端。
- 服务端用私钥对客户端报文进行解密,得到会话密钥。
双方后续的通信过程都使用该会话密钥进行对称加密。
SHH支持账号密码(准确地说是口令)认证和密钥认证。
SSH通过账号密码认证的过程很简单:客户端通过会话秘钥加密账号和密码发送给服务端,服务端解密后进行验证。
密钥认证的简略过程如下:
- 客户端用会话秘钥加密账号和自己的公钥发送给服务端。
- 服务端解密后验证该公钥是否在授权文件中,如果不在则拒绝连接;如果在授权文件中,则生成一个随机字符串并使用该公钥加密,然后再使用会话秘钥二次加密后发送给客户端。
- 客户端通过会话秘钥和自己的私钥解密得到服务端生成的随机字符串,用会话密钥加密后发送给服务端。
- 服务端通过会话秘钥解密客户端发来的随机字符串,如果和自己生成的一致,说明客户端确实持有对应的私钥,认证通过。否则认证失败。
SSH客户端会优先通过密钥进行认证,如果密钥不存在或认证失败,才会使用账号密码认证。在私钥文件不被泄露且选择了合适的密钥生成算法的情况下,目前的技术手段是不可能攻破密钥认证过程的,而密码认证总存在被暴力破解的可能性,而且密钥验证不需要手动输入密码,因此不管从安全性还是便利性,都应该优先使用密钥登录服务器。(我的云服务器在没有改SSH端口号之前,每天都会收到几万次尝试暴力破解密码的登录请求,虽然我已经在服务端设置成只允许使用密钥登录了QAQ
SSH登录命令
可以使用命令ssh <user_name>:<host_name>
进行SSH登录。<host_name>
可以是IP或域名。SSH服务端默认监听22号端口,因此前面的命令默认去连接22号端口,如果服务器的监听端口不是22,可以用-p
选项指定端口:ssh <user_name>:<host_name> -p <port>
。
在第一次登录到服务器时,会提示“远程主机具有xxx指纹,是否接受”,这个指纹就是SSH服务端的公钥的摘要。如果接受就会把<host_name>
和对应公钥写入~/.ssh/known-hosts
里,下次再登录就会比对<host_name>
和公钥,如果一致就接受;如果不一致会提示存在风险并终止通信过程。
摘要是指使用特定HASH算法生成的原始信息的特征,不同信息HASH出相同特征的情况称作HASH碰撞,一般情况下常用的HASH算法很难发生碰撞,所以经常被用来验证文件是否相同。一些比较老的MD5和SHA1等算法已经被证明存在破解方法(指可以人为产生碰撞),所以SSH使用更安全的SHA256算法。
如果客户端配置了密钥,输入上面的命令就可以直接登录到服务器,否则需要输入密码。但是即使配置了密钥,每次都要输入用户名和IP还是太麻烦了(懒才是第一生产力),可以把这些信息写入客户端配置文件(Linux和Windows都是~/.ssh/config
,是一个文本文件,可以用文本编辑器打开):
Host myhost # 可以是任意名字
HostName <host_name>
User <user_name>
Port <port>
这样就可以使用命令ssh myhost
进行登录或者scp <local_file> myhost:<remote_path>
进行文件传输。如果端口是默认的22,可以在配置文件中省略不写;如果有多个服务器,可以写入多个这样的配置块。
密钥生成与配置
使用命令ssh-keygen -t <type> -b <bit_length> -C <comment> -f <file_name> -N <password>
可以生成密钥对。
-
-t <type>
指定密钥的算法类型,默认是rsa
,但是该加密算法位数少了不够强,位数多了速度慢,推荐使用更优的ed25519
算法。ed25519
算法在OpenSSH 6.5(OpenSSH是SSH协议的一个开源实现,事实上的SSH标准)中引入,该版本于2014年发布,所以只要不是准备登录古董服务器,一般不用担心使用该算法会和服务端不兼容。 -
-b <bit_length>
指定密钥长度。ed25519
使用默认即可,如果执意要使用rsa
算法,建议指定2048以上。 -
-C <comment>
指定密钥的注释,默认为<user_name>@<host_name>
,这里的<host_name>
不是IP或域名,而是系统设置中的主机名。 -
-f <file_name>
指定生成的密钥文件名,默认情况下,私钥名为id_<type>
,公钥名为id_<type>.pub
,保存在~/.ssh
目录下。一般省略使用默认即可。 -
-N <password>
指定使用密钥时的密码,一般不需要设置,保管好私钥而不是靠密码保护才是正确的做法。
所以可以使用以下命令生成密钥对:ssh-keygen -t ed25519
。之后会让输入密钥存放路径和密码,一路回车留空,完成就会在~/.ssh
目录生成两个密钥文件id_ed25519
和id_ed25519.pub
。
生成密钥对之后,需要将公钥放到服务器的授权文件(~/.ssh/authorized_keys
)中,SSH服务端会用授权文件中的公钥进行校验,只有拥有相应私钥的SSH客户端才可以登录。
authorized_keys
和密钥文件均是文本文件,用文本编辑打开复制粘贴即可,authorized_keys
中每个公钥占一行。
进行上述设置之后SSH登录和SCP传输文件就不需要输入密码了。
authorized_keys
和密钥文件都是特别隐私的文件,因此SSH服务端和客户端都会校验对应的文件,如果文件不是仅当前用户有写入权限,就会拒绝登录。默认的~/.ssh
目录一般是只有当前用户可写的。客户端配置文件
客户端配置文件除了HostName
和User
等基本配置项外,还可以指定私钥文件和加密算法等。
IdentityFile <file_path>
:使用指定的私钥文件进行验证,需要注意文件权限问题。ServerAliveInterval <seconds>
:发送心跳连接的时间间隔。如果一定时间内没有通信,SSH连接就会断掉。为了避免中途掉线频繁登录,可以隔一段时间让客户端发送一个用于保持活跃的会话。因为是隔一段时间发送一次,且目的是告诉服务端我还活着,所以叫通常叫做心跳连接。ServerAliveCountMax <n>
:在断开连接前发送心跳连接的尝试次数。
服务端配置文件
Linux上的SSH服务端一般是一个叫做sshd的程序,配置文件是/etc/ssh/sshd_config
。配置文件中每一行都是一个<key> <value>
形式的配置项,用#
表示注释。编辑配置文件之后,需要重启服务才可以生效:systemctl restart sshd.service
,需要root权限。
常用的配置项如下:
推荐工具
Windows Terminal
:Windows下的开源终端工具,配置好了非常好用,可以使用ssh命令登录远程服务器。缺点是只能执行命令,没有图形化的远程文件管理界面。MobaXterm
:专门用于远程登录的工具,功能比较丰富,带有图形化的远程文件管理界面,但比较简陋。WinSCP
:专门用于远程文件管理的工具,传输文件比较方便,命令行功能比较简陋。VSCode
:介于IDE和编辑器之间的工具,安装Remote SSH插件之后拥有强大的远程连接功能,图形化远程文件管理和命令行功能兼具,且可以直接在服务器上写代码。缺点是会在服务器上安装VSCode服务端,由于其基于Electron,所以会占用相对较多的内存资源(正常使用几百兆到一两个G)。
信息查看
系统版本
Linux内核版本:cat /proc/version
或uname -a
发行版版本:lsb_release -a
或cat /etc/os-release
更详细的小版本信息每个发行版都可能不同:
- Debian:
cat /etc/debian_version
bash设置
提示符设置
在~/.bashrc
中设置PS1
的值:
PS1='\e[91m\u@\h\e[0m:\e[94m\w\e[0m# '
格式采用ANSI转义序列控制,其中\e[
表示转义序列开始,m
表示转义序列结束。91
代表亮红色,94
代表亮蓝色,0
表示重置所有设置。
\u
、\h
、\w
为bash变量,分别表示用户名、主机名(如果有多个则取第一个)、当前目录。
@
和#
为普通字符。最后的空格为了更容易区分输入的命令。
上面是为root
用户设置的,因此用了亮红色用户名和#
,普通用户可以尝试亮绿色(92
)和$
:
PS1='\e[92m\u@\h\e[0m:\e[94m\w\e[0m$ '
ANSI有关字符显示的转义码如下:
颜色 | 前景色 | 背景色 | 颜色 | 前景色 | 背景色 |
---|---|---|---|---|---|
黑 | 30 | 40 | 亮黑 | 90 | 100 |
红 | 31 | 41 | 亮红 | 91 | 101 |
绿 | 32 | 42 | 亮绿 | 92 | 102 |
黄 | 33 | 43 | 亮黄 | 93 | 103 |
蓝 | 34 | 44 | 亮蓝 | 94 | 104 |
洋红 | 35 | 45 | 亮洋红 | 95 | 105 |
青 | 36 | 46 | 亮青 | 96 | 106 |
白 | 37 | 47 | 亮白 | 97 | 107 |
其他样式:
- 0:重置所有样式
- 1:粗体
- 4:下划线
- 7:反显