Apache 和 SSH 的双因素身份验证系统
如果您为了自己使用而运行一个公开访问的 Web 服务器(并且让我们面对现实,如果您正在阅读Linux Journal,那么您很有可能这样做),您如何限制某人访问您的站点并做坏事的风险?SSH 呢,这是一个更大的问题?在当今世界,务必考虑您的风险敞口并采取措施尽可能限制风险。
在本教程中,我将逐步介绍实施自制双因素身份验证系统以访问您的网站和 SSH 访问所需的步骤。
基础设施和“挑战”运行您自己的硬件可能很麻烦。在处理硬件故障(例如风扇故障、电源故障、硬盘损坏等)之后,您最终可能会决定放弃您的主机托管或卧室壁橱以及您的硬件,并跃入弹性计算的世界。其中一种选择是 Amazon 的 EC2 平台,该平台提供各种 Linux 发行版,并且拥有最强大和成熟的云平台之一。我不是亚马逊的代表,但我第一个说尝试一下。这太棒了,而且微型实例免费一年。
在本文的测试场景中,我使用运行 Ubuntu 12.04 LTS 的 Amazon EC2 服务器来托管几个 Web 应用程序。如果您使用不同版本的 Linux,则可以轻松地调整说明以满足您的特定需求。让我们假设这些应用程序在很大程度上仅供个人使用。如果站点仅从工作场所或家庭访问,您只需创建防火墙规则以仅允许来自这些 IP 地址的 Web 流量即可保护站点。顺便说一句,这正是应该如何保护 SSH 的方法。
但是,让我们假设这不适用于您的 Web 应用程序,因为您经常出差,并且需要在旅途中访问这些应用程序,因此几个防火墙规则对您没有帮助。让我们还假设您的应用程序有自己的安全系统,但您仍然想要额外的安全层。
您可以设置 VPN 服务器,但偶尔您可能希望让家庭成员访问您的某个站点,因此 VPN 方法将不起作用。
另一个考虑因素是用于真正双因素身份验证的 Google Authenticator。您当然可以走这条路,但您正在寻找您可以自己完成的事情 - 一些自包含且属于您的东西。
就像 Linux 世界中的许多事情一样,有志者事竟成!事实证明,您可以轻松设置自己的自制双因素解决方案,并使用它来控制对您的 Web 应用程序和 SSH 的访问,同时还可以让其他用户偶尔访问您的站点。
Apache 身份验证和授权由于此示例的 Web 服务器是 Apache,让我们利用服务器的身份验证和授权功能,在将您的任何站点提供给用户之前,要求提供一组凭据。
为了保持简单,并且由于您将遵循最佳实践并仅允许 https 流量进出您的 Web 服务器,因此让我们使用 mod_auth_basic
模块进行身份验证。
首先成为 root 用户,并在您新安装的 Ubuntu 上安装 Apache
sudo su
apt-get install apache2
假设您的 Web 应用程序在主 www 文档文件夹的子文件夹中运行。这允许您通过在 http 服务器根文件夹中创建一个 .htaccess 文件来一次性处理您的所有站点
vim /var/www/.htaccess
现在,让我们添加几行代码,告诉 Apache 需要身份验证以及在哪里查找密码文件
AuthType Basic
AuthName "restricted area"
AuthUserFile /home/ubuntu/.htpasswd
require valid-user
完成此操作后,您现在需要更改文件的所有权,以便 Apache 进程可以读取其内容
chown www-data:www-data /var/www/.htaccess
接下来,您需要创建您在 .htaccess 文件中引用的 .htpasswd 文件,并配置其所有权,以便 Web 服务器可以读取它
htpasswd -cb /home/ubuntu/.htpasswd jameslitton test123
chown www-data:www-data /home/ubuntu/.htpasswd
现在您需要告诉 Apache 需要身份验证,并使用 mod_auth_basic
模块来实现此目的
vim /etc/apache2/sites-available/default-ssl
然后您需要将 AllowOverride None
更改为 AllowOverride AuthConfig
Service apache2 restart
现在访问您的站点会提示输入用户名和密码(图 1)。

图 1. 来自 mod_auth_basic
的身份验证请求
我在这里要采用的方法是让您的辅助身份验证密码每天更改一次,而不是更频繁地更改。这允许上面描述的 mod_auth_basic
方法工作。我不会在这里详细介绍,但可以说每次密码更改时,都需要立即重新身份验证,这不是您想要的行为。
让我们使用一个六位数字的 PIN 码,并在每天午夜将其发送到手机。我是 Pushover 的忠实粉丝,Pushover 是一项服务,可将即时通知从您自己的脚本和应用程序推送到手机和平板电脑。
要进行设置,请创建一个 bash 脚本
vim /home/ubuntu/2fac.sh
现在添加以下行
1 #!/bin/bash
2 ppwd=`od -vAn -N4 -tu4 < /dev/urandom | tr -d '\n' | tail -c 6`
3 curl -s -F "token=id" -F "user=id" -F "message=$ppwd"
↪https://api.pushover.net/1/messages.json
4 htpasswd -b /home/ubuntu/.htpasswd jameslitton $ppwd
5 echo $ppwd | base64 >/home/ubuntu/.2fac
第 2 行生成一个随机的六位 PIN 码,并将其分配给名为 ppwd 的变量。第 3 行将 PIN 码发送到 Pushover 服务,以便传送到您的手机。第 4 行使用新密码更新 .htpasswd 文件,最后但并非最不重要的一点是,第 5 行以您可以恢复的格式存储 PIN 码的副本,您稍后会看到。
现在保存脚本,并使其可执行
chmod +x /home/ubuntu/2fac.sh
要完成此解决方案,您只需通过 cron 计划脚本在每晚午夜运行
crontab -e
00 00 * * * /home/ubuntu/2fac.sh
使其可从 Web 访问
您当然可以将其保留在那里并称之为完成,但是假设您没有收到您的代码并且想要强制更改。或者,也许您给了某人对您站点的临时访问权限,现在您想要强制更改密码以确保该人不再可以访问该站点。您可以始终 SSH 连接到您的服务器并手动运行脚本,但这太难了。让我们创建一个可从 Web 访问的 PHP 脚本,它将为您处理此问题。
首先,更改您的 2fac.sh 脚本的所有权,以便您的 Web 服务器可以运行它
chown www-data:www-data /home/Ubuntu/2fac.sh
现在您需要创建一个新文件夹来保存您的脚本,并创建 PHP 脚本本身,该脚本允许手动运行新的“密钥”
mkdir /vaw/www/twofactor
vim /var/www/twofactor/index.php
1 <?php
2 exec('/home/ubuntu/2fac.sh');
3 header('Location: http://www.google.com');
4 ?>
因为可以想象您需要强制使用新密钥是因为您没有收到之前的密钥,所以您需要确保保存此脚本的文件夹不需要身份验证。为此,您需要修改 Apache 配置
vim /etc/apache2/sites-available/default-ssl
现在在 /var/www 的 Directory 指令下方添加以下内容
<Directory /var/www/twofactor/>
satisfy any
</Directory>
现在配置所有权并重启 Apache
chown -R www-data:www-data /var/www/twofactor
Service apache2 restart
因此,经过深思熟虑,可以想象 Pushover 服务可能会完全瘫痪。这将使您处于糟糕的境地,您无法访问您的站点。让我们为此场景构建一个应急计划。
为此,让我们构建第二个脚本,该脚本获取您的 PIN 码的副本(记住您之前保存的 .2fac 文件)并通过电子邮件发送给您。在这种情况下,让我们使用您的移动运营商的电子邮件到 SMS 网桥,通过 SMS 将消息发送给您。
首先安装 mailutils(如果您尚未安装),并确保选择 Internet 选项
apt-get install mailutils
现在创建第二个脚本
vim /home/Ubuntu/2fac2.sh
然后添加代码
#!/bin/bash
ppwd=`cat /home/ubuntu/.2fac | base64 --decode`
echo " " | mail -s $ppwd xxx5551212@vtext.com
不要忘记更改文件的所有权
chown www-data:www-data /home/ubuntu/2fac2.sh
chown www-data:www-data /home/ubuntu/.2fac
完成这些后,现在您需要修改 PHP 脚本
vim /var/www/twofactor/index.php
将第 2 行替换为以下内容
2 if (isset($_GET["sms"])) {
3 exec('/home/ubuntu/2fac2.sh');
4 } else {
5 exec('/home/ubuntu/2fac.sh');
6 }
然后创建两个书签,以便在任何时候您想要生成新的 PIN 码并通过 Pushover 发送给您时,您只需单击链接即可完成。第二个书签会将现有 PIN 码的副本发送到您选择的电子邮件地址,以应对 Pushover 服务不可用的极不可能发生的情况。
-
2Factor = https://www.thelittonfamily.com/twofactor/index.php
-
2Factor—SMS = https://www.thelittonfamily.com/twofactor/index.php?sms=1
将此解决方案扩展到涵盖 SSH 实际上非常简单。关键是使用您的 sshd_config 文件中鲜为人知的 ForceCommand
指令。这会强制 SSH 守护程序在跨越终端会话之前运行脚本。
让我们从脚本开始
vim /home/ubuntu/tfac-ssh.sh
现在添加以下行
1 #!/bin/bash
2 code=`cat .2fac | base64 --decode`
3 echo -ne "Enter PIN: "
4 while IFS= read -r -s -n1 pass; do
5 if [[ -z $pass ]]; then
6 echo
7 break
8 else
9 echo -n '*'
10 input+=$pass
11 fi
12 done
13 if [ $code = $input ];
14 then
15 sleep 1
16 clear
17 /bin/bash
18 else
19 sleep 1
20 curl -s -F "token=id" -F "user=id" -F "message=$input"
↪https://api.pushover.net/1/messages.json
21 fi
第 2 行将 PIN 码加载到变量中。第 3-12 行提示输入 PIN 码,并为每个按键回显一个星号。第 13 行将用户的输入与 PIN 码进行比较。如果它们匹配,则第 14-17 行清除屏幕并启动 bash 会话。如果用户的输入与 PIN 码不匹配,则第 18-21 行向 Pushover 发送通知,以便您知道发生了故障,然后结束会话。
让我们配置 SSH 守护程序来运行脚本
vim /etc/ssh/sshd_config
现在将以下内容添加到文件顶部
ForceCommand /home/ubuntu/tfac-ssh.sh

图 2. 来自 SSH 的双因素请求
这种方法效果很好。唯一的限制是没有退格键。如果您按错键,您的会话将被终止,您将不得不重试。
就这样,一个简陋的双因素身份验证实现就完成了,只需很少的努力,而且根据我的经验,它非常可靠!