如何在Ubuntu14.04和Debian8上使用Apache设置ModSecurity
介绍
ModSecurity 是一个免费的 Web 应用程序防火墙 (WAF),可与 Apache、Nginx 和 IIS 配合使用。 它支持灵活的规则引擎来执行简单和复杂的操作,并附带一个核心规则集 (CRS),其中包含 SQL 注入、跨站点脚本、特洛伊木马、不良用户代理、会话劫持和许多其他漏洞的规则。 对于 Apache,它作为附加模块加载,便于安装和配置。
先决条件
要遵循本教程,您将需要:
- 一个 Ubuntu 14.04 或 Debian 8 Droplet。
- 具有 sudo 权限的标准用户帐户,您可以按照 Ubuntu 14.04 或 Debian 8 的初始服务器设置教程进行设置。
- 一个 LAMP 堆栈,您可以按照 Ubuntu 14.04 或 Debian 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
自定义其他指令。 SecRequestBodyLimit
和 SecRequestBodyNoFilesLimit
指令限制了可以发布到 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
将以下内容粘贴到此文件中。 我们屏蔽的两个词是 blockedword1 和 blockedword2。
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_FILENAME
与 form.php
、REQUEST_METHOD
与 POST
以及 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 文档。