如何在Ubuntu14.04和Debian8上使用Apache设置ModSecurity

来自菜鸟教程
跳转至:导航、​搜索

介绍

ModSecurity 是一个免费的 Web 应用程序防火墙 (WAF),可与 Apache、Nginx 和 IIS 配合使用。 它支持灵活的规则引擎来执行简单和复杂的操作,并附带一个核心规则集 (CRS),其中包含 SQL 注入、跨站点脚本、特洛伊木马、不良用户代理、会话劫持和许多其他漏洞的规则。 对于 Apache,它作为附加模块加载,便于安装和配置。

先决条件

要遵循本教程,您将需要:

  • 一个 Ubuntu 14.04 或 Debian 8 Droplet。
  • 具有 sudo 权限的标准用户帐户,您可以按照 Ubuntu 14.04Debian 8 的初始服务器设置教程进行设置。
  • 一个 LAMP 堆栈,您可以按照 Ubuntu 14.04Debian 8 的教程进行安装。

第 1 步 — 安装 ModSecurity

在这一步中,我们将安装 ModSecurity。

首先,更新包索引文件。

sudo apt-get update

然后,安装 ModSecurity。

sudo apt-get install libapache2-mod-security2 -y

您可以使用以下命令验证 ModSecurity 模块是否已加载。

sudo apachectl -M | grep --color security2

如果输出显示为 security2_module (shared),则表明模块已加载。

ModSecurity 的安装包括一个必须重命名的推荐配置文件。

sudo mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

最后,重新加载 Apache。

sudo service apache2 reload

ModSecurity 的新日志文件将在 /var/log/apache2/modsec_audit.log 的 Apache 日志目录中创建。

第 2 步 — 配置 ModSecurity

开箱即用,ModSecurity 不做任何事情,因为它需要规则才能工作。 在这一步中,我们将首先启用一些配置指令。

要在此步骤中查找和替换配置指令,我们将使用流编辑器 sed。 您可以阅读 sed 教程系列 了解更多关于该工具的信息。

启用的基本指令

默认的 ModSecurity 配置文件设置为 DetectionOnly,它根据规则匹配记录请求并且不阻止任何内容。 这可以通过编辑 modsecurity.conf 文件并修改 SecRuleEngine 指令来更改。 如果您在生产服务器上尝试此操作,请仅在测试所有规则后更改此指令。

sudo sed -i "s/SecRuleEngine DetectionOnly/SecRuleEngine On/" /etc/modsecurity/modsecurity.conf

SecResponseBodyAccess 指令配置响应体是否被缓冲(即 由 ModSecurity 阅读)。 只有在需要数据泄漏检测和保护时才需要这样做。 因此,将其打开会耗尽 Droplet 资源并增加日志文件的大小,因此我们将其关闭。

sudo sed -i "s/SecResponseBodyAccess On/SecResponseBodyAccess Off/" /etc/modsecurity/modsecurity.conf

要修改的可选指令

您可能希望通过编辑 /etc/modsecurity/modsecurity.conf 自定义其他指令。 SecRequestBodyLimitSecRequestBodyNoFilesLimit 指令限制了可以发布到 Web 应用程序的最大数据。

特别是,SecRequestBodyLimit 指令指定了最大 POST 数据大小。 如果客户端发送任何更大的内容,服务器将响应 413 Request Entity Too Large 错误。 如果您的 Web 应用程序没有任何文件上传,则该值可以保持不变。 配置文件中指定的预配置值为 13107200 字节(12.5MB)。 如果要更改此值,请查找以下行 modsecurity.conf

可选的 `modsecurity.conf` 指令更改

SecRequestBodyLimit 13107200

同样,SecRequestBodyNoFilesLimit 限制 POST 数据减去文件上传的大小。 当有人发送非常大的请求正文时,应将此值设置得尽可能低,以降低对拒绝服务 (DoS) 攻击的敏感性。 配置文件中预配置的值为131072字节(128KB)。 如果要更改此值,请查找以下行 modsecurity.conf

可选的 `modsecurity.conf` 指令更改

SecRequestBodyNoFilesLimit 131072

影响服务器性能的指令是 SecRequestBodyInMemoryLimit。 该指令几乎是不言自明的; 它指定了应将多少“请求主体”数据(POSTed 数据)保存在内存(RAM)中,更多内容将放置在硬盘中(就像交换一样)。 因为 Droplets 使用 SSD,所以这不是什么大问题。 但是,如果您有空闲的 RAM,则可以更改此设置。 该指令的预配置值为 128KB。 如果要更改此值,请查找以下行 modsecurity.conf

可选的 `modsecurity.conf` 指令更改

SecRequestBodyInMemoryLimit 131072

第 3 步 — 测试 SQL 注入

在配置一些规则之前,我们将创建一个易受 SQL 注入攻击的 PHP 脚本来测试 ModSecurity 的保护。

注意:这是一个基本的 PHP 登录脚本,没有会话处理或表单清理。 仅作为示例测试 SQL 注入和 ModSecurity 的规则。 它将在教程结束前删除。


首先,访问 MySQL 提示符。

mysql -u root -p

在这里,创建一个名为 sample 的 MySQL 数据库并连接到它。

create database sample;
connect sample;

然后创建一个包含一些凭据的表——用户名 sammy 和密码 password

create table users(username VARCHAR(100),password VARCHAR(100));
insert into users values('sammy','password');

最后,退出 MySQL 提示符。

quit;

接下来,在 Apache 的文档根目录中创建登录脚本。

sudo nano /var/www/html/login.php

将以下 PHP 脚本粘贴到文件中。 请务必将以下脚本中的 MySQL 密码更改为您之前设置的密码,以便脚本可以连接到数据库:

/var/www/html/login.php

<html>
<body>
<?php
    if(isset($_POST['login']))
    {
        $username = $_POST['username'];
        $password = $_POST['password'];
        $con = mysqli_connect('localhost','root','your_mysql_password','sample');
        $result = mysqli_query($con, "SELECT * FROM `users` WHERE username='$username' AND password='$password'");
        if(mysqli_num_rows($result) == 0)
            echo 'Invalid username or password';
        else
            echo '<h1>Logged in</h1><p>This is text that should only be displayed when logged in with valid credentials.</p>';
    }
    else
    {
?>
        <form action="" method="post">
            Username: <input type="text" name="username"/><br />
            Password: <input type="password" name="password"/><br />
            <input type="submit" name="login" value="Login"/>
        </form>
<?php
    }
?>
</body>
</html>

该脚本将显示一个登录表单。 打开浏览器并导航到 http://your_server_ip/login.php 以查看它。 如果您输入正确的一对凭据,例如 在 用户名 字段中输入 sammy 并在 密码 字段中输入密码,您将看到消息 这是仅在使用有效凭据登录时显示的文本 。 如果您导航回登录屏幕并使用不正确的凭据,您将看到消息 Invalid username or password

接下来的工作是尝试 SQL 注入来绕过登录页面。 在用户名字段中输入以下内容。

SQL注入用户名

' or true -- 

请注意,在 -- 之后应该有一个空格才能使此注入起作用。 将密码字段留空,然后点击登录按钮。 该脚本显示了针对经过身份验证的用户的消息! 在下一步中,我们将防止这种情况发生。

第 4 步 — 设置规则

在这一步中,我们将设置一些 ModSecurity 规则。

启用 CRS

为了让事情变得更容易,ModSecurity 已经安装了很多规则。 这些称为 CRS(核心规则集),位于 /usr/share/modsecurity-crs 目录中。 要加载这些规则,我们需要配置 Apache 读取这些目录下的 .conf 文件,因此打开 security2.conf 文件进行编辑。

sudo nano /etc/apache2/mods-enabled/security2.conf

在文件的最后一行 (</IfModule>) 之前添加以下两个指令,以红色突出显示。

更新了 security2.conf

        IncludeOptional /etc/modsecurity/*.conf
        IncludeOptional "/usr/share/modsecurity-crs/*.conf"
        IncludeOptional "/usr/share/modsecurity-crs/activated_rules/*.conf"
</IfModule>

保存并关闭文件。

排除目录/域(可选)

有时,如果某个特定目录或域名正在运行一个应用程序(如 phpMyAdmin),则排除它是有意义的,因为 ModSecurity 会阻止 SQL 查询。 最好排除 WordPress 等 CMS 应用程序的管理后端。 如果您在新服务器上学习本教程,则可以跳过此步骤。

要为完整的 VirtualHost 禁用 ModSecurity,请将以下指令放在其虚拟主机文件的 <VirtualHost>[...]</VirtualHost> 块中。

<IfModule security2_module>
    SecRuleEngine Off
</IfModule>

省略特定目录(例如,/var/www/wp-admin):

<Directory "/var/www/wp-admin">
    <IfModule security2_module>
        SecRuleEngine Off
    </IfModule>
</Directory>

如果您不想在目录中完全禁用 ModSecurity,请使用 SecRuleRemoveById 指令通过指定其 ID 来删除特定规则或规则链。

<LocationMatch "/wp-admin/update.php">
    <IfModule security2_module>
        SecRuleRemoveById 981173
    </IfModule>
</LocationMatch>

激活 SQL 注入规则

接下来,我们将激活 SQL 注入规则文件。 所需的规则文件应符号链接到 activated_rules 目录,类似于 Apache 的 mods-enabled 目录。 切换到 activated_rules 目录。

cd /usr/share/modsecurity-crs/activated_rules/

然后从 modsecurity_crs_41_sql_injection_attacks.conf 文件创建符号链接。

sudo ln -s ../base_rules/modsecurity_crs_41_sql_injection_attacks.conf .

最后,重新加载 Apache 以使规则生效。

sudo service apache2 reload

现在打开我们之前创建的登录页面,尝试在用户名字段上使用相同的 SQL 注入查询。 因为我们在步骤 2 中将 SecRuleEngine 指令更改为 On,所以会显示 403 Forbidden 错误。 (如果 SecRuleEngine 留给 DetectionOnly 选项,注入将成功,但尝试将记录在 modsec_audit.log 文件中。)

因为此 PHP 登录脚本仅用于测试 ModSecurity,所以您应该在测试完成后将其删除。

sudo rm /var/www/html/login.php

第 5 步 — 编写自己的规则

在本节中,我们将创建一个规则链,如果在 HTML 表单中输入了通常与垃圾邮件相关的某些词,则该规则链会阻止请求。

首先,我们将创建一个示例 PHP 脚本,该脚本从文本框中获取输入并将其显示给用户。 打开一个名为 form.php 的文件进行编辑。

sudo nano /var/www/html/form.php

粘贴以下代码:

/var/www/html/form.php

<html>
    <body>
        <?php
            if(isset($_POST['data']))
                echo $_POST['data'];
            else
            {
        ?>
                <form method="post" action="">
                        Enter something here:<textarea name="data"></textarea>
                        <input type="submit"/>
                </form>
        <?php
            }
        ?>
    </body>
</html>

自定义规则可以添加到任何配置文件或放置在 ModSecurity 目录中。 我们将把我们的规则放在一个名为 modsecurity_custom_rules.conf 的单独的新文件中。

sudo nano /etc/modsecurity/modsecurity_custom_rules.conf

将以下内容粘贴到此文件中。 我们屏蔽的两个词是 blockedword1blockedword2

modsecurity_custom_rules.conf

SecRule REQUEST_FILENAME "form.php" "id:'400001',chain,deny,log,msg:'Spam detected'"
SecRule REQUEST_METHOD "POST" chain
SecRule REQUEST_BODY "@rx (?i:(blockedword1|blockedword2))"

SecRule 的语法是 SecRule VARIABLES OPERATOR [ACTIONS]。 在这里,我们使用链操作将变量 REQUEST_FILENAMEform.phpREQUEST_METHODPOST 以及 REQUEST_BODY 与正则表达式 (@rx) 字符串 (blockedword1|blockedword2)?i: 进行不区分大小写的匹配。 在所有这三个规则匹配成功时,ACTION 是拒绝并与 msg "Spam detected." 记录链动作模拟逻辑与以匹配所有三个规则。

保存文件并重新加载 Apache。

sudo service apache2 reload

在浏览器中打开 http://your_server_ip/form.php。 如果输入包含blockedword1 或blockword2 的文本,您将看到一个403 页面。

因为此 PHP 表单脚本仅用于测试 ModSecurity,所以您应该在测试完成后将其删除。

sudo rm /var/www/html/form.php

结论

在本教程中,您学习了如何安装和配置 ModSecurity,以及添加自定义规则。 要了解更多信息,您可以查看 官方 ModSecurity 文档