Secure Shell(安全外壳协议,简称SSH)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。SSH通过在网络中创建安全信道来实现SSH客户端与服务器之间的连接。SSH最常见的用途是远程登录系统,人们通常利用SSH来传输命令行界面和远程执行命令。
使用SSH进行远程登录主要经历两个阶段,第一阶段是安全信道的建立,第二阶段是用户认证。
第一阶段的介绍可参考5. PKI - SSH建立安全信道的过程。
第二阶段用户认证支持公钥认证、密码认证和主机认证三种认证方式。
1. 公钥认证
公钥认证的步骤大致如下:
1.1 客户端发送公钥验证请求给服务器
其中包含user name、service name、认证方式"pblickey"、公钥算法名称、公钥内容(可以是证书)等。其中公钥算法名称不受密钥交换时算法的限制。
byte SSH_MSG_USERAUTH_REQUEST
string user name in ISO-10646 UTF-8 encoding [RFC3629]
string service name in US-ASCII
string "publickey"
boolean FALSE
string public key algorithm name
string public key blob
1.2 服务器发送公钥验证结果给客户端
服务器收到消息后进行校验,如果服务器不支持客户端的公钥算法,则会拒绝认证请求。如果验证通过返回用户认证公钥OK的消息给客户端。
byte SSH_MSG_USERAUTH_PK_OK
string public key algorithm name from the request
string public key blob from the request
如果验证失败返回用户认证失败的消息。
byte SSH_MSG_USERAUTH_FAILURE
name-list authentications that can continue
boolean partial success
1.3 客户端发送认证请求给服务器
客户端不论是否收到服务器的公钥验证结果,直接发送认证请求给服务器。以下是发送包的内容。
byte SSH_MSG_USERAUTH_REQUEST
string user name
string service name
string "publickey"
boolean TRUE
string public key algorithm name
string public key to be used for authentication
string signature
与公钥验证请求相比,多了签名信息。签名使用与认证公钥对应的私钥进行,签名在以下内容,以下顺序的基础上进行。
string session identifier
byte SSH_MSG_USERAUTH_REQUEST
string user name
string service name
string "publickey"
boolean TRUE
string public key algorithm name
string public key to be used for authentication
1.4 服务器进行公钥和签名校验
服务器首先对公钥进行认证,如果公钥认证通过,则利用该公钥对签名进行验证。如果两者均校验通过,则认为公钥认证成功。服务器会发送认证成功消息给客户端。
byte SSH_MSG_USERAUTH_SUCCESS
2. 密码认证
2.1 客户端发送密码认证请求给服务器
密码认证使用下面的包进行。其中用户名、密码信息均用明文表示,密码用ISO-10646 UTF-8编码方式进行编码。报文在传输层进行加密,服务器和客户端都会校验传输层的机密性,如果传输层不具有机密性,则密码认证会被禁用。
byte SSH_MSG_USERAUTH_REQUEST
string user name
string service name
string "password"
boolean FALSE
string plaintext password in ISO-10646 UTF-8 encoding [RFC3629]
2.2 服务器返回密码认证结果给客户端
服务器对用户名、密码进行认证。如果认证成功则返回认证成功。
byte SSH_MSG_USERAUTH_SUCCESS
已过期密码是不能用于密码认证的。如果密码已经过期,服务器会发送变更密码响应给客户端。
byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ
string prompt in ISO-10646 UTF-8 encoding [RFC3629]
string language tag [RFC3066]
2.3 客户端发送变更密码请求给服务器
客户端收到变更密码消息后,可以选择使用不同的认证方式认证,或者请求一个新的密码并重试密码认证。此时发送的消息包如下:
byte SSH_MSG_USERAUTH_REQUEST
string user name
string service name
string "password"
boolean TRUE
string plaintext old password in ISO-10646 UTF-8 encoding
[RFC3629]
string plaintext new password in ISO-10646 UTF-8 encoding
[RFC3629]
2.4 服务器处理请求并返回处理结果
如果密码变更成功且认证成功,返回:
byte SSH_MSG_USERAUTH_SUCCESS
如果密码变更成功,但需要更多认证,返回:
byte SSH_MSG_USERAUTH_FAILURE
name-list authentications that can continue
boolean TRUE
变更密码失败,或者是因为不支持密码变更,或者是旧密码错误。但是如果服务器已经发送了密码变更的报文,我们知道服务器是支持密码变更的。返回:
byte SSH_MSG_USERAUTH_FAILURE
name-list authentications that can continue
boolean FALSE
由于新密码未被接受导致密码变更失败(如密码太简单),返回:
SSH_MSG_USERAUTH_CHANGEREQ
3. 主机认证
有些网站希望基于用户本地主机和远程主机上的用户名进行认证。这种认证方式不适合应用与于保密级别高的网站,但在某些环境下会比较方便。这种认证方式是可选的。使用这种认证方式时要特别注意防止普通用户获取本地主机的私钥。
3.1 客户端发送主机认证请求给服务器
客户端使用客户端主机的私钥进行签名,发送签名给服务器。
byte SSH_MSG_USERAUTH_REQUEST
string user name
string service name
string "hostbased"
string public key algorithm for host key
string public host key and certificates for client host
string client host name expressed as the FQDN in US-ASCII
string user name on the client host in ISO-10646 UTF-8 encoding
[RFC3629]
string signature
签名使用主机私钥在以下内容、以下顺序的基础上进行。
string session identifier
byte SSH_MSG_USERAUTH_REQUEST
string user name
string service name
string "hostbased"
string public key algorithm for host key
string public host key and certificates for client host
string client host name expressed as the FQDN in US-ASCII
string user name on the client host in ISO-10646 UTF-8 encoding
[RFC3629]
3.2 服务器发送认证结果给客户端
服务器使用客户端主机公钥对请求签名进行验证。