配置Linux主机的两步验证登陆是个看起来很简单,实际上很麻烦的一件操作,主要是SSH和PAM配置的注意事项很多,需要在配置时保持一个SSH的连接,以备不时之需。

2025.05 河北·保定·定州·定州博物馆 东汉中山穆王刘畅的银缕玉衣

背景

两步验证

  1. 什么是两步验证
  2. 如何使用两步验证

安全缺陷

  1. ManyTimePad攻击
  2. OTP绕过
  3. OTP机器人

实施

现在有一台stand alone的ECS放到公网上访问,由于某些原因用ACL限制SSH登陆有点麻烦。现在就是使用密钥登陆+OTP的形式来实现合规。

另,系统使用Fedora 41。

安装

1
2
3
4
# 系统更新
dnf -y update
# 安装google-authenticator以及在终端生成二维码的工具qrencode
dnf install -y google-authenticator qrencode qrencode-libs

配置

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# google-authenticator 的认证配置
[root@beijing ~]# google-authenticator
# 是否需要开启OTP
Do you want authentication tokens to be time-based (y/n) y
# 因为网络原因会报一个fail的错误
Warning: pasting the following URL into your browser exposes the OTP secret to Google:
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/root@beijing%3Fsecret%3D7ZA2DON54L6RRA3XST4XCOZ3PE%26issuer%3Dbeijing
# 此处应当加载一个二维码图片来实现手机扫码
Failed to use libqrencode to show QR code visually for scanning.
Consider typing the OTP secret into your app manually.
# 需要把下面的key手动添加到手机或者其他版本的OTP工具中去
Your new secret key is: 7ZA2DON54L6RRA3XST4XCOZ3PE
Enter code from app (-1 to skip): 284247
Code confirmed
# 应急密码
Your emergency scratch codes are:
41512988
16324046
36557372
11539062
54599229
# 是否更新
Do you want me to update your "/root/.google_authenticator" file? (y/n) y
# 是否禁止同一验证码多次使用
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
# 是否允许使用过期验证码
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) y
# 是否限制尝试频率,减少SSH爆破风险
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

# 系统的PAM模块加载
echo "auth required pam_google_authenticator.so nullok" >>/etc/pam.d/sshd
sed -i 's/auth substack password-auth/# auth substack password-auth/g' /etc/pamd.d/sshd
# 配置仅使用证书和OTP认证
echo "AuthenticationMethods publickey,keyboard-interactive" >>/etc/ssh/sshd_config
sed -i 's/ChallengeResponseAuthentication no/ChallengeResponseAuthentication yes/g' /etc/ssh/sshd_config.d/50-redhat.conf

# 配置某个用户使用密码和OTP认证
Match user sujx
AuthenticationMethods password,keyboard-interactive

# 重启SSHD服务
systemctl restart sshd

验证