如何在Ubuntu14.04上保护Nginx
即使使用默认设置,Nginx 也是一个非常安全可靠的 Web 服务器。 但是,有很多方法可以进一步保护 Nginx。
在本文中,我们将专门使用开源软件,同时尝试遵循一些流行的 Web 服务器加固方法和安全标准。 也就是说,我们将讨论防止信息泄露、强制加密、执行审计和限制访问。
先决条件
在学习本教程之前,请确保您完成以下先决条件:
- Ubuntu 14.04 Droplet(请参阅(Initial Server Setup with Ubuntu 14.04 for details)
- 按照 How To Install Nginx on Ubuntu 14.04 LTS 中的说明安装和配置 Nginx Web 服务器
- 已注册的域或子域指向 Droplet 的 IP。 您将需要它来测试 SSL 设置。 有关更多信息,请阅读有关 如何从公共域注册商指向 DigitalOcean 名称服务器 的文章。
- 非 root sudo 用户(查看 Initial Server Setup with Ubuntu 14.04 了解详情)
除非另有说明,本教程中所有需要 root 权限的命令都应以具有 sudo 权限的非 root 用户身份运行。
第 1 步 — 更新所有软件
将您的软件更新到最新版本是保护整个系统的第一步,而不仅仅是 Nginx。
警告:在更新系统上的所有软件包之前,请务必确定这是否会导致系统上运行的除 Nginx 之外的任何东西出现问题。 在执行一次影响这么多包的操作之前,备份整个系统是个好主意。 如果在更新所有软件包后出现问题,您可以恢复到备份。 要更新存储库包列表,然后在 Ubuntu 服务器上使用 apt-get
管理所有当前安装的包,请运行以下命令:
sudo apt-get update && sudo apt-get upgrade
或者,您可以将 Nginx 升级到 Ubuntu 存储库中的最新版本。 这将升级 Nginx 包和任何必要的依赖项:
sudo apt-get upgrade nginx
第二步——防止信息泄露
要开始强化您的 Nginx Web 服务器,让我们从限制它披露的信息开始。 从 HTTP 服务器标头到应用程序错误报告的各个级别都会泄露有价值的信息。
因此,让我们从 HTTP 标头开始。 默认情况下,Nginx 在 HTTP 标头中显示其名称和版本。 您可以像这样使用 curl
检查此信息:
curl -I http://localhost
输出应如下所示:
Output of curl -I http://localhostHTTP/1.1 200 OK Server: nginx/1.4.6 (Ubuntu) ...
如您所见,在上面的输出中可以看到 Nginx 的版本和操作系统的名称。 这不一定是一个严重的问题,而是攻击者试图解决以破坏您的 Nginx 服务器的难题的一部分。 这就是为什么我们将通过使用 nano 打开 Nginx 的主配置文件 /etc/nginx/nginx.conf
来隐藏这些信息,如下所示:
sudo nano /etc/nginx/nginx.conf
然后,在 http
配置部分内添加 server_tokens off;
行,如下所示:
/etc/nginx/nginx.conf
http { ## # Basic Settings ## server_tokens off; ...
之后,保存并退出文件,然后重新加载 Nginx 以使更改生效:
sudo service nginx reload
现在,如果您再次尝试相同的 curl 命令:
curl -I http://localhost
你会看到更少的信息:
Output of curl -I http://localhostHTTP/1.1 200 OK Server: nginx ...
上面的输出仅揭示了这是一个 Nginx 服务器的事实。 您可能想知道是否也可以删除它。 不幸的是,这并不容易实现,因为它没有配置选项。 相反,您将不得不从源代码重新编译 Nginx,这是不值得的。
除了 Server
标头之外,还有另一个包含敏感信息的标头 - X-Powered-By
。 此标头通常显示 PHP、Tomcat 或 Nginx 后面的任何服务器端引擎的版本。 如果您使用 PHP 运行 Nginx,curl
的输出将如下所示:
Output of curl -I http://localhost on nginx with phpHTTP/1.1 200 OK Server: nginx ... X-Powered-By: PHP/5.5.9-1ubuntu4.14 ...
上面的 X-Powered-By
标头显示服务器是运行 PHP 版本 5.5.9 的 Ubuntu 14。 从 X-Powered-By
标头中隐藏此信息非常重要。 您不能在 Nginx 中执行此操作,但您应该在后端引擎中找到相应的选项。 例如,对于 PHP,您必须在主 php.ini
配置文件中设置选项 expose_php = Off
。 默认情况下,此选项设置为 On
。
接下来要做的是更改 4xx(客户端)错误页面,攻击者可以从中使用这些信息。 通常,这些是 Unauthorized 401
和 Forbidden 403
错误页面。 除非您正在调试问题,否则通常不需要向普通访问者显示这些错误。 如果您需要了解这些错误,您仍然可以在 Nginx 错误日志 (/var/log/nginx/error.log
) 中找到它们。
要更改这两个错误页面,请打开服务器块的配置文件,例如默认的:
sudo nano /etc/nginx/sites-enabled/default
在主服务器 server
配置部分中指定:
/etc/nginx/sites-enabled/default
server { ... error_page 401 403 404 /404.html; ...
保存对文件的更改后,请确保重新加载 Nginx 以使其通过以下命令生效:
sudo service nginx reload
以上提示为您提供了防止信息泄露的想法 - 尽可能少地显示非必要的 Web 内容。 您不仅应该在 Nginx 中隐藏服务和调试信息,还应该在后端引擎(PHP、Tomcat 等)中,当然还有在 Web 应用程序中隐藏服务和调试信息。
第 2 步 — 配置 SSL
在 Nginx 上运行带有 SSL 的安全 HTTPS 协议对于任何处理敏感信息(如用户凭据、私人数据等)的站点来说都是必须的。 SSL 是确保无论您的站点用户在哪里以及他们使用何种 Internet 连接,他们接收和发送的信息都将受到保护的唯一方法。
文章 How To Create an SSL Certificate on Nginx for Ubuntu 14.04 解释了如何使用默认 HTTPS 配置轻松设置免费 SSL。 虽然本文是一个好的开始,但它不会有效地保护您的数据。 如今,默认的 SSL 设置和算法不足以阻止攻击者解密您的流量。
这就是为什么我们要为 Nginx 配置一个 SSL 证书,使用更强的加密算法和设置。 这将确保为您的数据提供更高级别的保护,并且您的 HTTPS 服务将符合最高安全标准和实践。
让我们开始使用以下命令为我们的 SSL 证书创建一个目录:
sudo mkdir /etc/nginx/ssl/
对于我们的 SSL,我们需要一个具有强签名算法 SHA256 的证书。 出于测试目的或非生产环境,您可以使用自签名证书并忽略 SSL 警告。 让我们使用以下命令创建一个:
sudo openssl req -x509 -nodes -sha256 -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt
此命令将询问您一些有关您的站点和业务详细信息的简单问题。 之后,它将在文件 /etc/nginx/ssl/nginx.key
中创建一个 2048 位 RSA 加密密钥,并在文件 /etc/nginx/ssl/nginx.crt
中创建一个 SHA256 证书。
接下来,您必须生成更强大的 4096 位长 DH 参数 。 准备好等待一段时间,这取决于您的 Droplet,可能需要长达 30 分钟。 运行命令:
sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096
现在您可以配置服务器块的 SSL 部分。 例如,让我们配置默认服务器块。 打开其配置文件以使用 nano 进行编辑:
sudo nano /etc/nginx/sites-enabled/default
在此文件中,编辑服务器配置部分,在 server_name
指令之后添加 SSL 部分,如下所示:
/etc/nginx/sites-enabled/default
server { ... server_name localhost; ### SSL Part listen 443 ssl; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'; ssl_prefer_server_ciphers on; ssl_dhparam /etc/nginx/ssl/dhparam.pem; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; ...
以下是我们使用上述指令指定的指令:
listen
— 在端口 443 上启用 SSL 侦听器,即 HTTPS 端口。ssl_protocols
— 仅启用这三个被认为是当前安全的协议 -TLSv1 TLSv1.1 TLSv1.2
。ssl_ciphers
— 仅启用以下安全 SSL 密码:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
ssl_prefer_server_ciphers
— 确保客户端尊重服务器的密码偏好。ssl_dhparam
— 使用我们之前生成的自定义、强 DH 参数。ssl_certificate
— 使用我们的自签名 SSL 证书。 如果您使用其他证书,请务必更改它。ssl_certificate_key
— 使用我们之前生成的 SSL 私钥。
要使上述设置生效,您必须使用以下命令重新加载 nginx:
sudo service nginx reload
要测试您的新 SSL 配置,最好使用外部工具,例如 SSL Labs 提供的工具。 在那里,您应该忽略 SSL 不受信任的警告。 这是很自然的,因为它是自签名证书。 请注意,此站点将仅测试具有注册域名的站点。 您不能仅使用 Droplet 的 IP 地址测试 SSL 连接。
总体结果应该是“T”,就像“测试”一样,但本质上它是 A(可能的最高值),它应该像这样显示 "If trust issues are ignored: A"
:
稍后,您可能希望删除 SSL 警告并使 SSL 测试成为干净的“A”。 一种选择是使用 Let's Encrypt,如文章 How To Secure Nginx with Let's Encrypt on Ubuntu 14.04 中所述。 它是免费的,允许您指定最大为 4096 的 RSA 密钥大小,并且不会发出关于自签名的警告。 否则,您可以选择任何商业 SSL 提供商。 当您选择一个时,请确保您选择了 SHA256 证书。
第 3 步 — 通过 IP 限制访问
密码身份验证并不总是足以确保站点敏感区域的安全,例如站点控制面板、phpmyadmin 等。 有时,攻击者会利用此类区域中的弱密码或软件漏洞来获得未经授权的访问。 这就是为什么强烈建议添加额外的 IP 限制,前提是您可以确定合法用户的 IP。
例如,如果您有一个 WordPress 站点,并且其管理区域位于 /wp-admin/
,则应将对其的访问限制为您的 IP 或所有管理员的 IP。 为此,打开相应的服务器块 — Nginx 的默认服务器块是 /etc/nginx/sites-enabled/default
:
sudo nano /etc/nginx/sites-enabled/default
在 server
配置部分内添加:
/etc/nginx/sites-enabled/default
server { ... location /wp-admin/ { allow 192.168.1.1/24; allow 10.0.0.1/24; deny all; } ... ...
在上面,请确保将 192.168.1.1
和 10.0.0.1
替换为您的 IP。 同样,您可以通过更改网络掩码 (/24
) 来允许其他 IP 甚至网络的访问。
要使此类设置生效,您必须使用以下命令重新加载 Nginx:
sudo service nginx reload
现在,如果您尝试使用超出允许 IP 地址范围的浏览器访问站点的 /wp-admin/
部分,您将收到错误消息。 此错误将是 403 Forbidden(除非您已将此错误更改为 404 Not found 如前所述)。 同时你会在错误日志中看到真正的错误代码,使用命令:
sudo tail /var/log/nginx/error.log
access forbidden
错误将显示如下:
Output of sudo tail -f /var/log/nginx/error.log... 2016/01/02 04:16:12 [error] 4767#0: *13 access forbidden by rule, client: X.X.X.X, server: localhost, request: "GET /wp-admin/ HTTP/1.1", host: "Y.Y.Y.Y" ...
将不止一种方法应用于安全性的组合,例如更改错误页面和限制 IP 访问,显示了强化 Nginx 的累积效应。 根据示例,攻击者和他们使用的自动化工具将看到 404 not found 页面,而不是通常的 WordPress 管理页面。 这令人困惑,可能会阻止他们尝试其他方法来破坏您的 WordPress。
第 4 步 — 执行安全审计
独立于您自己的意见进行安全检查总是一个好主意。 为此,您可以使用扫描 Web 漏洞的安全审计工具。 有很多这样的工具,包括商业工具,首先你可以使用免费和开源的 wapiti。 Wapiti 可能缺少一些更高级工具的功能,但它会让您了解什么是安全审计。
您可以通过 apt 在 Ubuntu 上安装 wapiti:
sudo apt-get install wapiti
然后使用 wapiti 使用以下命令开始扫描您的站点:
wapiti http://example.org -n 10 -b folder
确保将 example.org
替换为您的站点名称。 我们为该命令提供了两个附加参数。 第一个 -n 10
将具有相同模式的 URL 的数量限制为 10 个,以防止死循环。 第二个参数 -b folder
仅将扫描范围设置为给定域。
扫描完成后,您将在运行扫描的目录中名为 generated_report
的目录中获得结果。 为了获得最佳查看效果,请将此目录下载到您的本地计算机并使用 Web 浏览器打开 index.html
文件。
在报告中,您将看到按 10 个不同类别分类的漏洞:SQL 注入、盲 SQL 注入、文件处理、跨站点脚本、CRLF、命令执行、资源消耗、Htaccess 绕过、备份文件和潜在危险文件。
理想情况下,您的报告应该如下所示,没有发现任何漏洞:
如果有漏洞,可以展开相应部分的扫描了解更多信息。
确保经常使用不同的工具运行此类扫描,以确保对您的 Nginx 和网站进行最完整和彻底的审核。
第 5 步 — 采取额外的安全措施
一些关于 Nginx 安全的话题没有在本文中涉及,因为已经有关于它们的优秀文章。 请熟悉以下内容:
Naxsi 是 Nginx 的 Web 应用程序防火墙。 它通过使用恶意签名的汇编来保护您免受已知和未知的 Web 漏洞的侵害。
您应该知道 Naxsi 是一个复杂的软件,它的调整需要一些时间和精力。 幸运的是,大多数流行的 Web 应用程序都有现成的配置,如果需要,您可以进一步自定义。
Fail2ban 是一个很好的工具,可以将网络安全提升到一个新的水平并主动保护您的 nginx 服务器。 到目前为止,我们已限制用户查找某些信息和访问我们网站的某些部分。 使用 fail2ban,当您检测到攻击者正在执行恶意活动时,您可以在特定时间段内进一步阻止攻击者。
监控对安全至关重要,Monit 是一个很好的工具,它对 Nginx 有很好的支持。 Web 日志不仅显示了恶意活动的痕迹,而且还显示了 CPU 负载和内存使用量的峰值。
在本文中,请特别注意第 5 步 — 监控日志中的错误和关键字。 在那里,您可以配置自定义警报,以便在发生安全事件时发送,例如当有人访问或尝试访问您网站的敏感部分时。
拥有防火墙对于您的 nginx 和整个 droplet 的安全非常重要。 确保将 https (tcp 443) 端口添加到除了标准 http (tcp 80) 端口之外的允许传入连接。
文件和目录完整性检查器(例如 AIDE)会针对文件和目录的更改发出警报。 这对于 Web 文件特别方便,因为您应该知道站点的某些部分何时更改以及添加了新文件/目录。 要了解有关 AIDE 的更多信息,您可以从文章开始。
上面的文章有点过时了,并不是专门为 Ubuntu 写的。 但是,您应该能够轻松地对其进行调整并将其应用于 Ubuntu 14.04。 当您配置 AIDE 或其他类似工具时,请确保将您的 Web 日志和临时文件(例如 Web 缓存)排除在监控之外。
结论
阅读本文后,您应该对 Nginx 的安全性更有信心。 只需确保在功能和安全性之间寻找平衡,这样您就可以放心,您的 Web 环境按设计运行且安全。 另外,请记住,保护 Nginx 是一项持续的任务,需要定期更新、重新配置、扫描等。