文章

为SSH登录添加双重身份验证(2FA)

为SSH登录添加双重身份验证(2FA)

Google Authenticator 使用一次性密码(One-time Passcodes)(OTP)进行两步验证,集成在Linux的 PAM 系统中。

  • HOTP:基于 HMAC 计数的一次性密码
  • TOTP:基于时间的一次性密码

如果使用过Google Authenticator二次验证器的话你肯定知道,添加密钥的方式有两种:一种是扫描二维码添加密钥,另外一种是手动输入密钥。 若要扫码添加,则需要在终端生成配置二维码,需要额外安装 qrencode 软件包。

参考:谷歌/谷歌身份验证器-libpam

1. 安装 Google Authenticator PAM 模块

启动终端会话并键入:

1
2
# ubuntu/Debian
sudo apt install libpam-google-authenticator

2. 配置 SSH

(1). 启用Google Authenticator PAM 模块

要使 SSH 启用 Google Authenticator PAM 模块,请将以下行添加到/etc/pam.d/sshd文件中:

1
auth required pam_google_authenticator.so

这样将会首先询问二次验证码,验证成功后才会询问密码,二者都要成功验证后才允许登录。 交换 pam_google_authenticator.sosystem-remote-login 两行会改变验证顺序。

若要二者任一正确 即可登陆,将配置信息修改为

1
auth sufficient pam_google_authenticator.so

此时会先询问二次验证码,若正确则直接登录到系统,否则验证密码,两者任一正确即可登录系统。

可选参数:

如果使用 HOTP (基于计数器而不是基于时间),请添加no_increment_hotp选项以确保计数器不会因失败而递增 尝试。多次密码尝试失败不会被锁定 用户账号

1
 auth required pam_google_authenticator.so  no_increment_hotp

此 PAM 模块的可选参数 :

1
2
3
4
5
6
7
8
9
10
11
12
13
# 确保 counter (对于 HOTP 模式) 不会因失败的尝试而递增。
# 建议设置,因为没有令牌的攻击者的密码尝试失败不会被锁定 授权用户。
auth required pam_google_authenticator.so   no_increment_hotp

# 如果用户尚未设置OTP,则允许用户在没有OTP的情况下登录
auth required pam_google_authenticator.so   nullok

# 不自动调整时间偏差,最常见的是 服务器时钟与 Android 上的时钟不一样。
# PAM 模块尝试补偿 time skew,最多偏移3次(每次等待30s),将获得三个不同的 TOTP 代码
auth required pam_google_authenticator.so   noskewadj

# Store 密钥 文件位于特定位置
auth required pam_google_authenticator.so   secret=/var/unencrypted-home/${USER}/.google_authenticator

(2). 修改SSH配置项

修改 sshd 配置文件(/etc/ssh/sshd_config), 开启质疑-应答认证选项,找到以下两项:

  • ChallengeResponseAuthentication
  • UsePAM

将其修改为 yes

1
2
3
4
5
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no  # >> 修改为 yes,开启质疑-应答认证选项
UsePAM yes                          # >> 启用UsePAM模块
PasswordAuthentication yes          # >> 允许密码认证

重新启动sshd

(3). 针对于使用 Public key 的用户

如果使用密钥登录ssh,还需要做一些编辑

编辑 /etc/ssh/sshd_config文件

加上 AuthenticationMethods publickey,keyboard-interactive

接下来重启sshd

1
sudo systemctl restart sshd

然后再编辑 /etc/pam.d/sshd 这个文件

通过 # 注释掉 ` @include common-auth`

注意⚠️:如果当前你设置使用密钥(public key)登陆并禁止密码登录, OpenSSH 会忽略如上所有的配置,若想使用密钥登陆 同时开启二次验证的话你需要几个额外步骤: 添加或修改/etc/ssh/sshd_config配置文件 :

  • 配置项 KbdInteractiveAuthentication yes
  • 配置项 ChallengeResponseAuthentication yes
  • 配置项 AuthenticationMethods publickey,keyboard-interactive:pam

默认的 PAM 认证规则中包含密码认证,既然只用密钥和二次验证码登陆系统,则需要修改 sshd 的 PAM 规则,编辑/etc/pam.d/sshd文件,关闭密码验证:

1
2
3
4
5
6
7
8
/etc/pam.d/sshd
#%PAM-1.0
#auth     required  pam_securetty.so      #>> disable remote root
auth      required  pam_google_authenticator.so
#auth      include   system-remote-login  #>> 在行首添加注释符,关闭密码登录规则。
account   include   system-remote-login
password  include   system-remote-login
session   include   system-remote-login

(4). 重新配置验证码?

如果需要重新配置验证码,再次执行google-authenticator命令即可,将新的二维码扫描进入2FA验证程序后就好了

3. 生成密钥文件

提示✅:可选安装 qrencode 软件包以在屏幕上生成可以扫描的二维码。扫描二维码以自动配置两次验证器。

每一个想要使用 2FA 的用户需要在其用户目录生成一个密钥文件,使用命令 google-authenticator 来完成:

它会问你一系列问题,下面是一个推荐的配置:

  • Make tokens “time-base”“: yes
  • 更新/.google_authenticator:yes
  • 不允许多次使用:yes
  • 提高原始生成时限:no
  • 启用速率限制:yes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
$ google-authenticator                                                             
Do you want authentication tokens to be time-based (y/n) y 
  (# 是否基于时间的认证,如果选择n,则为基于计数的认证-HTOP)
Warning: pasting the following URL into your browser exposes the OTP secret to Google:
  <这里是自动生成的二维码>
Your new secret key is: J4T4C4HYT2KIA52WGSDJEOLM2I (# 验证器配置密钥)
Enter code from app (-1 to skip): 269371           (# 输入验证器生成的验证码)
Code confirmed
Your emergency scratch codes are:                  (# 紧急备用令牌码)
  93394730
  14394073
  33491911
  86112157
  22174783

Do you want me to update your "/home/username/.google_authenticator" file? (y/n) y
  (# 是否重新生成 google_authenticator 配置文件?)
  (# 如果想停用这个用户的二次验证,只需要删除用户 Home 目录下的该文件就可以了)

Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y
  (# 是否拒绝多次重复使用相同的令牌?这将限制你每30s仅能登录一次,但会提醒/阻止中间人攻击。)
 
By default, a new token is generated every 30 seconds by the mobile app.
In order to compensate for possible time-skew between the client and the server,
we allow an extra token before and after the current time. This allows for a
time skew of up to 30 seconds between authentication server and client. If you
experience problems with poor time synchronization, you can increase the window
from its default size of 3 permitted codes (one previous code, the current
code, the next code) to 17 permitted codes (the 8 previous codes, the current
code, and the 8 next codes). This will permit for a time skew of up to 4 minutes
between client and server.
Do you want to do so? (y/n) n
  (# 是否将验证码有效窗口时间由1分30秒增加到约4分钟?这将缓解时间同步问题。)

If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting? (y/n) y
  (# 是否启用此模块的登录频率限制,登录者将会被限制为最多在30秒内登录3次。)

建议将备用令牌码保存在安全的地方(打印出来并放在一个安全的位置),因为当丢失手机(即你的两步验证器)或其他原因不能使用两步验证器时,只能使用备用令牌码登录。它们同时也被保存在~/.google_authenticator,你可以在登录后随时查阅。

google-authenticator命令的 可选参数如下:

1
2
3
4
5
6
# -t: 使用 TOTP 验证
# -f: 将配置保存到 ~/.google_authenticator 文件里面
# -d: 不允许重复使用以前使用的令牌
# -w 3: 使用令牌进行身份验证以进行时钟偏移,偏移3次
# -e 5: 生成 5 个紧急备用代码
# -r 3 -R 30: 限速 - 每 30 秒允许 3 次登录

4. 测试验证

在完成测试前请不要断开目前已经的 SSH 连接!如果配置出错或者无法登陆还可以有补救的机会,否则失联的痛楚就要一人默默感受了!

5. 其他配置

用于桌面登陆

谷歌2次认证插件可以同时用于控制台与 GNOME 桌面登录。 只需要在文件 /etc/pam.d/login/etc/pam.d/gdm-password 内加入: auth required pam_google_authenticator.so

配置备份

希望能够备份 google-authenticator配置,然后在另一台设备上恢复这些配置,而不是手动运行以重新生成配置文件

配置文件位于用户主目录中 ~/.google_authenticator

注意目录权限需要设置当前用户只读chmod 400 -R ~/.google_authenticator

密钥文件存储位置

如果想要改变密钥存储位置,请使用 --secret 参数:

google-authenticator --secret="/PATH_FOLDER/USERNAME" 然后更改/etc/pam.d/sshd内的路径配置:

1
2
/etc/pam.d/sshd
auth required pam_google_authenticator.so user=root  secret=/PATH_FOLDER/${USER}

user=root 用于强制PAM使用root用户权限来搜索文件。 另外请注意,密钥文件的所有者是root,生成文件的用户只能读取文件(chmod: 400):

1
2
chown root.root /PATH_FILE/SECRET_KEY_FILES
chmod 400 /PATH_FILE/SECRET_KEY_FILES
本文由作者按照 CC BY 4.0 进行授权