用MFA加固PAM

2020 05 8, Fri

我第一个云服务器只用了不到一天,准确一些来说四个小时,然后就被人爆了密码。后来用了很多方法,现在比较稳定下来的方法就是2FA,实质上来说就是一次性密码。

今天我们上很多网站,都可以用单次密码来进行登录,比如说短信验证码,或者有各种各样的身份验证器。

一次性密码

传统的静态密码,大部分用户都会设置一个常见的字符串作为密码,这使得骇客可以用彩虹表的方法轻易查到密码明文。即使密码比较长、没有规律,我们也可以用暴力猜解的方式破解出密码。

所以有种思路是,在静态密码上增加一层动态的密码,来提高安全性。一般来说动态密码实时生成、有有效期,大部分是完全随机,破解的可能性很小。

举个例子,我们今天网页登录苹果帐号,我们的Mac上会弹出一个6位的数字,每次都不一样,从而验证网页登录的是本人。登录坚果云时会通过短信或者微信发送验证码。不少网站还提供了验证器,比如说Steam令牌就是其中一种。

TOTP/HOTP

Google给我们提供了一个可以访问的、易于接入的方案:Google Authenticator。

Google Authenticator支持两种一次性密码,TOTP和HOTP。两种都有一个初始的秘密。

HOTP全程是HMAC based One Time Password。是一种基于事件和次数的OTP。每一次验证完成后都会给一个反馈,同时两边都会记录:下次我要用新的了。

而TOTP全称是Time based One Time Password。是基于时间的OTP,定期刷新,中间留够你输入验证码的时间。

相对来说TOTP用的更多一些,因为用户,比如说我们自己,都是不可靠的,

PAM

PAM全称是可拔插式身份验证模块,是Linux的一个核心模块,openssh啊窗口管理器啊,还有cockpit这类,只要涉及到登录的,很多都是利用PAM。

配置文件在/etc/pam.d中,每个应用有自己的配置文件。比如说我们今天要用到的ssh和cockpit的配置文件分别是/etc/pam.d/sshd/etc/pam.d/cockpit

How

安装Google Authenticator

Google Authenticator有一个手机App。

同时也有Linux的软件包叫google-authenticator,应该可以从各个发行版的仓库中直接安装。CentOS需要先启用epel-release仓库。

推荐同时安装qrencode,可以直接展示一个二维码,用手机扫描一下就好了。

在服务一侧给每个用户生成自己的密钥

很多web服务可以帮你生成密钥,比如说jumpserver。

不过我们用的cockpit和ssh本身没这功能。但是如果需要生成密钥,也只是需要运行一个命令:

google-authenticator -t -d -f -r 3 -R 30

其中-t表示基于时间,-d表示一个OTP只能用一次、不可重用,-f表示强制覆盖,-r 3 -R 30表示30秒内可以重试3次。

执行以后,会问你手机上的一次性密码是多少。

有qrencode的话,用手机扫一下二维码,就会得出来结果并且把秘密保存在手机里面。如果没有二维码,手动添加一个就好,选择基于时间,填好密钥就行。

把手机上的一次性密码填到终端里面就会把密钥保存到本地。

添加PAM模块

在服务对应的PAM配置中添加一行

auth       required     pam_google_authenticator.so nullok

上面是说身份验证时需要用Google Authenticator。如果用户没有创建Authenticator的密钥,就会忽略这步。如果所有用户都需要Google Authenticator的话,就需要提前先都生成好,去掉nullok。

ssh

ssh需要多一步,否则无法正常输入一次性密码。

修改/etc/sshd_config修改或增加一行配置:

ChallengeResponseAuthentication yes

除此之外还有一个权限问题。看后面。

重启服务

sudo systemctl restart sshd
sudo systemctl restart cockpit

然后再去登录cockpit或者ssh就会提示你,需要输入Verification Code,打开App,输入现在的一次性密码,成功登录,大功告成。

可能会遇到的问题

SELinux

可能会遇到sshd无法创建读写文件的问题。

最好在第一次登录前,在服务器上把SELinux设置为Permissive,登录完成以后执行:

sudo ausearch -c 'sshd' --raw | audit2allow -M my-sshd
sudo semodule -X 300 -i my-sshd.pp

应该生成了一个my-sshd.pp和my-sshd.te文件。te是SELinux的策略文件。大致是这样:

module my-sshd 1.0;

require {
	type sshd_t;
	type user_home_dir_t;
	class file { create getattr open read rename setattr unlink write };
}

#============= sshd_t ==============
allow sshd_t user_home_dir_t:file { getattr rename create open read setattr unlink write };

重启一下服务一般就没有大问题了。