2006-10
21

前面介绍cygwin下安装sshd时简单地提到了ssh的公钥认证。 下面将这种认证方式详细地解释一下。


为什么要使用公钥认证

通常,通过ssh登录远程服务器时,使用密码认证,分别输入用户名和密码,两者满足一定规则就可以登录。 但是密码认证有以下的缺点:

  • 用户无法设置空密码(即使系统允许空密码,也会十分危险)
  • 密码容易被人偷窥或猜到
  • 服务器上的一个帐户若要给多人使用,则必须让所有使用者都知道密码,导致密码容易泄露,而且修改密码时必须通知所有人

而使用公钥认证则可以解决上述问题。

  • 公钥认证允许使用空密码,省去每次登录都需要输入密码的麻烦
  • 多个使用者可以通过各自的密钥登录到系统上的同一个用户

公钥认证的原理

所谓的公钥认证,实际上是使用一对加密字符串,一个称为公钥(public key), 任何人都可以看到其内容,用于加密;另一个称为密钥(private key),只有拥有者才能看到,用于解密。 通过公钥加密过的密文使用密钥可以轻松解密,但根据公钥来猜测密钥却十分困难。

ssh 的公钥认证就是使用了这一特性。服务器和客户端都各自拥有自己的公钥和密钥。 为了说明方便,以下将使用这些符号。

Ac客户端公钥
Bc客户端密钥
As服务器公钥
Bs服务器密钥

在认证之前,客户端需要通过某种方法将公钥 Ac 登录到服务器上。

认证过程分为两个步骤。

  1. 会话密钥(session key)生成
    1. 客户端请求连接服务器,服务器将 As 发送给客户端。
    2. 服务器生成会话ID(session id),设为 p,发送给客户端。
    3. 客户端生成会话密钥(session key),设为 q,并计算 r = p xor q。
    4. 客户端将 r 用 As 进行加密,结果发送给服务器。
    5. 服务器用 Bs 进行解密,获得 r。
    6. 服务器进行 r xor p 的运算,获得 q。
    7. 至此服务器和客户端都知道了会话密钥q,以后的传输都将被 q 加密。
  2. 认证
    1. 服务器生成随机数 x,并用 Ac 加密后生成结果 S(x),发送给客户端
    2. 客户端使用 Bc 解密 S(x) 得到 x
    3. 客户端计算 q + x 的 md5 值 n(q+x),q为上一步得到的会话密钥
    4. 服务器计算 q + x 的 md5 值 m(q+x)
    5. 客户端将 n(q+x) 发送给服务器
    6. 服务器比较 m(q+x) 和 n(q+x),两者相同则认证成功

服务器端设置

使用公钥认证需要对服务器进行一些设置。修改 /etc/sshd_config 的以下配置。

RSAAuthentication yes        # 启用 RSA 认证
PubkeyAuthentication yes     # 启用公钥认证
PasswordAuthentication no    # 禁止密码认证

然后重新启动 sshd。

/etc/init.d/ssh restart

客户端设置

Linux

假设客户端的用户 charlee 要以 guest 用户登录到服务器上。 首先在客户端执行下面的命令。

[charlee@client:~]$ ssh-keygen -t rsa
Generating public/private rsa1 key pair.
Enter file in which to save the key (/home/charlee/.ssh/id_rsa):
Enterpassphrase (empty for no passphrase):  输入密码
Enter same passphrase again:   再次输入密码
Your identification has been sabed in /home/charlee/.ssh/id_rsa
Your public key has been saved in /home/charlee/.ssh/id_rsa.pub

生成的文件保存在主目录的 .ssh 目录下,id_rsa为客户端密钥,id_rsa.pub 为客户端公钥。

之后,通过 U 盘等方式将公钥 id_rsa.pub 复制到服务器上,并执行下列命令。

[guest@server:~]$ cat id_rsa.pub >> .ssh/authorized_keys

其中 id_rsa.pub 是客户端的用户 charlee 的公钥。

这样在客户端即可通过以下的命令连接服务器。

[charlee@client:~]$ ssh -l guest server

若不想每次登录服务器时都输入密码,可以先执行下列命令:

[charlee@client:~]$ ssh-add
Enter passphrase for /home/charlee/.ssh/id_rsa: 输入密码
Identity added: /home/charlee/.ssh/id_rsa (/home/charlee/.ssh/id_rsa)

以后登录服务器就不需要输入密码了。

Windows

假设我们使用putty连接ssh服务器。 为了使用公钥认证,我们需要同时下载 puttygen 这个工具来生成 putty 所使用的密钥。

使用Linux下生成的公钥和密钥的情况

如果你按照上面的介绍,在Linux下生成了公钥和密钥的话, 那么需要利用 puttygen 将密钥转换成 putty 使用的格式。

将Linux下生成的密钥 id_rsa 复制到 Windows 下。 启动 puttygen,然后单击Load按钮,选择文件类型为所有文件,然后选择 id_rsa,打开。 若在生成密钥时输入了密码,则打开时需要输入该密码。 之后就可以在 puttygen 的主界面上单击 Save private key,保存成 putty 格式的密钥。

使用puttygen生成公钥和密钥

你也可以利用 puttygen 直接生成公钥和密钥。打开 puttygen,然后在画面下方的 Parameters 栏选择加密算法和加密长度(一般取默认值即可),最后单击 Generate。画面上会出现一个进度条, 在界面上随意移动鼠标以生成随机数。最后提示生成结束,单击 Save private key 按钮保存密钥。 最后将上方的Public key for pasting into OpenSSH authorized_keys file栏中的内容复制到 Linux 下 用户主目录下的 ~/.ssh/authorized_keys 文件中。

设置 putty 使用公钥认证

先在putty中设置好连接的主机名、端口等信息(说明省略)。使用公钥认证需要设置两个地方: 一个是 Connection 中的 Auto-login username,输入在服务器上的用户名;另一个是 Connection->SSH->Auth中的 Private key file for authentication, 选择刚才转换或生成的 .ppk 格式的密钥。之后即可使用公钥认证进行连接了。



这篇文章有 8 条评论了,快来一起讨论讨论吧!
#1
fcicq
2006-10-21 19:04

呵呵,这密钥文件携带也很麻烦.没有真正保险的介质.
偶觉得暂时比较好的方式是一次性密码.

#2
weiz
2008-04-17 11:48

这是公钥,遗失了也没有关系,要和你主机上的私钥配对使用才有效。

#3
charlee
2008-04-17 11:59

@weiz 谢谢,其实fcicq想说的是,当你要在不同的地方登录同一台服务器,你就得将密钥随身携带了。

#4
shirdrn
2008-09-17 16:36

请教一下:
关于认证的过程中,客户端计算出MD5值需要加密后发送到服务器端进行比较验证,那么这个客户端MD5值是使用服务器端公钥加密,还是使用客户端密钥加密后进行传输的?

#5
charlee
2008-09-17 21:34

@shirdrn 不好意思已经记不大清了,查了查资料,应该是不加密直接传输的吧。

#6
shirdrn
2008-09-18 10:22

哦,谢谢。

#7
ssh 公钥方式认证攻略 - 张飞博客
2009-06-12 21:44

[...] 为什么要使用公钥认证 [...]

#8
zy
2009-12-15 16:15

这是SSH客户端的认证方法,有没有相应的服务端身份认证方法,比如我用putty登录server_1,但是第一个IP包就被server_2截获了,它想冒充server_1,这该怎么配置认证呢?我现在的经验是用服务端公钥fingerprint,它在putty首次登录一个未记录的站点时会提示(提示是否保存),把它的值和事先在服务端计算好的公钥fingerprint比对是否相同,即采用散列校验的办法。
有没有更好的办法,比如同样是基于SSL的HTTPS,可以用上一级的信任机构签名公钥的办法来认证服务器,SSH服务端是否也能用这种被签名的公钥(证书)呢?

添加评论

Security Code: