Apache 和 SSH 的双因素身份验证系统

作者:James Litton

如果您为了自己使用而运行一个公开访问的 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 的身份验证请求

一次性每日密码/PIN

我在这里要采用的方法是让您的辅助身份验证密码每天更改一次,而不是更频繁地更改。这允许上面描述的 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

将此解决方案扩展到涵盖 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 的双因素请求

这种方法效果很好。唯一的限制是没有退格键。如果您按错键,您的会话将被终止,您将不得不重试。

就这样,一个简陋的双因素身份验证实现就完成了,只需很少的努力,而且根据我的经验,它非常可靠!

加载 Disqus 评论