如何在Ubuntu 14.04上保护Nginx

即使使用默认设置,Nginx也是一个非常安全可靠的Web服务器。但是,有很多方法可以进一步保护Nginx。

在本文中,我们将专门使用开源软件,同时尝试遵循一些流行的Web服务器强化方法和安全标准。也就是说,我们将讨论防止信息泄露,实施加密,执行审计和限制访问。

准备

在学习本教程之前,请确保完成以下内容:

  • Ubuntu 14.04 CVM,没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后再购买服务器。
  • 安装和配置Nginx Web服务器。
  • 已注册的域或子域指向CVM的IP。您将需要它来测试SSL设置。
    • 如果你有域名,保护你网站的最简单方法是使用腾讯云SSL证书服务,它提供免费的可信证书。腾讯云SSL证书安装操作指南进行设置。
    • 如果你没有域名,建议您先去这里注册一个域名,如果你只是使用此配置进行测试或个人使用,则可以使用自签名证书,不需要购买域名。自签名证书提供了相同类型的加密,但没有域名验证公告。关于自签名证书,你可以参考为Apache创建自签名SSL证书和如何为Nginx创建自签名SSL证书这两篇文章。
  • 具有sudo命令权限的非root用户(有关详细信息,请查看Linux系统下给非root用户添加sudo权限)

除非另有说明,否则本教程中需要root权限的所有命令都应作为具有sudo权限的非root用户运行。

第一步 - 更新所有软件

将软件更新到最新版本是保护整个系统的第一步,而不仅仅是Nginx。

警告:在更新系统上的所有软件包之前,请务必确定这是否会导致除Nginx之外的系统上运行的任何问题。在执行一次影响这么多包的操作之前,最好先备份整个系统。如果在更新所有软件包后出现问题,您可以恢复备份。要更新存储库软件包列表,然后用apt-get更新在Ubuntu服务器上管理的所有当前安装的软件包,请运行以下命令:

代码语言:javascript
复制
sudo apt-get update && sudo apt-get upgrade

或者,您可以将Nginx升级到Ubuntu存储库中的最新版本。这将升级Nginx包和任何必要的依赖项:

代码语言:javascript
复制
sudo apt-get upgrade nginx

第二步 - 防止信息泄露

要开始强化您的Nginx Web服务器,我们首先要限制它公开的信息。从HTTP服务器标头到应用程序错误报告的每个级别都泄露了有价值的信息。

所以让我们从HTTP标头开始。默认情况下,Nginx在HTTP标头中显示其名称和版本。你可以这样检查这些信息curl

代码语言:javascript
复制
curl -I http://localhost

输出应如下所示:

代码语言:javascript
复制
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
...

如您所见,在上面的输出中可以看到Nginx的版本和操作系统的名称。这不一定是一个严重的问题,而是攻击者试图解决以破坏您的Nginx服务器的难题的一部分。这就是为什么我们通过像这样用nano 打开Nginx的主配置文件/etc/nginx/nginx.conf来隐藏这些信息的原因:

代码语言:javascript
复制
sudo nano /etc/nginx/nginx.conf

然后,在http配置部分内添加server_tokens off;行:

代码语言:javascript
复制
http {
​
        ##
        # Basic Settings
        ##
        server_tokens off;
...

之后,保存并退出该文件,然后重新加载Nginx以使更改生效:

代码语言:javascript
复制
sudo service nginx reload

现在,如果再次尝试相同的curl命令:

代码语言:javascript
复制
curl -I http://localhost

您将看到更少的信息:

代码语言:javascript
复制
HTTP/1.1 200 OK
Server: nginx
...

以上输出仅公开了这是Nginx服务器的事实。你可能想知道你是否也可以删除它。不幸的是,这并不容易实现,因为它没有配置选项。相反,你将不得不从源代码重新编译Nginx,这是值得的。

除了Server标题之外,还有另一个包含敏感信息的标题 - X-Powered-By。此标头通常显示PHP,Tomcat或Nginx背后的任何服务器端引擎的版本。如果你用PHP运行Nginx,输出curl将如下所示:

代码语言:javascript
复制
HTTP/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 401Forbidden 403错误页面。除非您正在调试问题,否则通常不需要向常规访问者显示这些错误。如果您需要了解这些错误,您仍然可以在Nginx错误日志(/var/log/nginx/error.log)中找到它们。

要更改这两个错误页面,请打开服务器块的配置文件,例如默认值:

代码语言:javascript
复制
sudo nano /etc/nginx/sites-enabled/default

在主服务器server配置部分内指定:

代码语言:javascript
复制
server {
...
        error_page 401 403 404 /404.html;
...

将更改保存到文件后,请确保重新加载Nginx,以使其对命令生效:

代码语言:javascript
复制
sudo service nginx reload

以上提示为您提供了防止信息泄露的想法 - 尽可能少地显示非必要的Web内容。您不仅应该在Nginx中隐藏服务和调试信息,还应该在后端引擎(PHP,Tomcat等)中隐藏服务和调试信息,当然还应该隐藏在Web应用程序中。

第二步 - 配置SSL

在Nginx上运行带有SSL的安全HTTPS协议是处理敏感信息(如用户凭据,私人数据等)的任何站点必须的。SSL是确保无论您的站点用户位于何处以及Internet连接的唯一方法,他们使用,他们收到和发送的信息将受到保护。

虽然本文是一个良好的开端,但它无法有效保护您的数据。如今,默认的SSL设置和算法不够强大,无法阻止攻击者解密您的流量。

这就是为什么我们将使用更强大的加密算法和设置为Nginx配置SSL证书。这将确保为您的数据提供更高级别的保护,您的HTTPS服务将符合最高安全标准和实践。

让我们从使用以下命令为SSL证书创建目录开始:

代码语言:javascript
复制
sudo mkdir /etc/nginx/ssl/

对于我们的SSL,我们需要一个带有强签名算法SHA256的证书。出于测试目的或非生产环境,您可以使用自签名证书并忽略SSL警告。让我们用命令创建一个:

代码语言:javascript
复制
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参数。准备好等待一段时间,取决于你的CVM,它可能需要长达30分钟。运行命令:

代码语言:javascript
复制
sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096

现在,您可以配置服务器块的SSL部分。例如,让我们配置默认服务器块。使用nano进行编辑配置文件:

代码语言:javascript
复制
sudo nano /etc/nginx/sites-enabled/default

在此文件中,编辑服务器配置部分,在server_name指令之后添加SSL部分,如下所示:

代码语言:javascript
复制
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:

代码语言:javascript
复制
sudo service nginx reload

要测试新的SSL配置,最好使用外部工具,例如SSL Labs提供的工具。在那里你应该忽略SSL不受信任的警告。这很自然,因为它是一个自签名证书。请注意,此站点仅测试具有注册域名的站点。您无法仅使用CVM的IP地址测试SSL连接。

整体结果应该是“T”,就像“测试”一样,但基本上它是A(最高可能),它应该这样说"If trust issues are ignored: A"

稍后,您可能希望删除SSL警告并使SSL测试成为“A”。一种选择是使用** Let's Encrypt **,如在Ubuntu 14.04上如何使用Let's Encrypt来保护Nginx一文中所述。它是免费的,允许您指定最多4096的RSA密钥大小,并且不会发出有关自签名的警告。否则,您可以选择任何商业SSL提供商。当您选择一个时,请确保您选择SHA256证书。

第三步 - 通过IP限制访问

密码身份验证并不总是足以确保站点敏感区域的安全性,例如站点控制面板,phpmyadmin等。有时,攻击者利用这些区域中的弱密码或软件漏洞来获取未经授权的访问。这就是为什么强烈建议您添加额外的IP限制,前提是您可以确定合法用户的IP。

例如,如果您有一个WordPress站点并且其管理区域位于/wp-admin/,则应将其访问权限仅限于您的IP或所有管理员的IP。为此,打开相应的服务器块 - Nginx的默认服务器块是/etc/nginx/sites-enabled/default

代码语言:javascript
复制
sudo nano /etc/nginx/sites-enabled/default

server配置部分内添加:

代码语言:javascript
复制
server {
...
    location /wp-admin/ {
        allow 192.168.1.1/24;
     allow 10.0.0.1/24;
        deny  all;
}
...
...

在上面请确保更换192.168.1.110.0.0.1您的IP。同样,您可以通过更改网络掩码(/24)来允许访问其他IP甚至网络。

要使这些设置生效,您必须使用以下命令重新加载Nginx:

代码语言:javascript
复制
sudo service nginx reload

现在,如果您尝试使用/wp-admin/允许的IP地址范围之外的浏览器访问站点的某个部分,则会出现错误。此错误将为403 禁止页(除非您已将此错误更改为404未找到,如前所述)。同时,您将使用以下命令在错误日志中看到真正的错误代码:

代码语言:javascript
复制
sudo tail /var/log/nginx/error.log

access forbidden错误将表明这样的:

代码语言:javascript
复制
...
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找不到的页面,而不是通常的WordPress管理页面。这很令人困惑,可能会阻止他们尝试其他方法来破坏你的WordPress。

第四步 - 执行安全审计

独立于您自己的意见进行安全检查始终是个好主意。为此,您可以使用安全审核工具来扫描Web漏洞。有许多这样的工具,包括商业工具,一开始你可以使用免费和开源的wapiti。Wapiti可能缺乏更高级工具的一些功能,但它会让您了解安全审核的内容。

你可以通过apt在Ubuntu上安装wapiti:

代码语言:javascript
复制
sudo apt-get install wapiti

然后使用以下命令开始使用wapiti扫描您的站点:

代码语言:javascript
复制
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和网站进行最全面和最彻底的审核。

第五步 - 采取额外的安全措施

有关Nginx安全性的一些主题未在本文中介绍,因为已有关于它们的优秀文章。请熟悉以下内容:

  • 如何在Ubuntu 14.04上安装和配置Naxsi

Naxsi是Nginx的Web应用程序防火墙。它通过使用恶意签名的汇编来保护您免受已知和未知的Web漏洞的攻击。

您应该知道Naxsi是一个复杂的软件,它的调整需要一些时间和精力。幸运的是,大多数流行的Web应用程序都有现成的配置,您可以根据需要进一步自定义。

Fail2ban是一个很好的工具,可以将Web安全性提升到一个新的水平,并主动保护您的nginx服务器。到目前为止,我们限制用户查找某些信息并访问我们网站的部分内容。使用fail2ban,当您检测到攻击者正在执行恶意活动时,您可以进一步阻止攻击者。

监控对于安全至关重要,Monit是一个很好的工具,可以为Nginx提供良好的支持。Web日志不仅显示恶意活动的痕迹,而且还显示CPU负载和内存使用量的峰值。

在本文中,要特别注意第五步 - 监视错误和关键字的日志。在那里,您可以配置自定义警报,以便在安全事件发送时发送,例如当有人访问或尝试访问您站点的敏感部分时。

  • 如何在Ubuntu 14.04上使用Iptables设置防火墙

拥有防火墙对于nginx和整个CVM的安全性非常重要。确保将https(tcp 443)端口添加到标准http(tcp 80)端口之外的允许传入连接。

上面的文章有点过时,不是专门为Ubuntu编写的。但是,您应该能够轻松地对其进行调整并将其应用于Ubuntu 14.04。配置AIDE或其他类似工具时,请确保排除Web日志和临时文件(如Web缓存)的监视。

结论

阅读本文后,您应该对Nginx安全性更有信心。只需确保在功能和安全性之间寻求平衡,这样您就可以放心,您的Web环境按设计运行且安全可靠。另外,请记住,保护Nginx是一项持续性任务,需要定期更新,重新配置,扫描等。

想要了解更多关于Ubuntu的开源信息教程,请前往腾讯云+社区学习更多知识。

参考文献:《How To Secure Nginx on Ubuntu 14.04》