标签 Nginx 下的文章

NGINX 能在 web 性能中取得领先地位,这是由于其软件设计所决定的。许多 web 服务器和应用程序服务器使用一个简单的基于线程或进程的架构,NGINX 立足于一个复杂的事件驱动的体系结构,使它能够在现代硬件上扩展到成千上万的并发连接。

下面这张深入 NGINX 的信息图从高层次的进程架构上深度挖掘说明了 NGINX 如何在单一进程里保持多个连接。这篇博客进一步详细地解释了这一切是如何工作的。

知识 – NGINX 进程模型

Master Process

为了更好的理解这个设计,你需要理解 NGINX 如何运行的。NGINX 有一个主进程(它执行特权操作,如读取配置和绑定端口)和一些工作进程与辅助进程。

# service nginx restart
* Restarting nginx
# ps -ef --forest | grep nginx
root     32475     1  0 13:36 ?        00:00:00 nginx: master process /usr/sbin/nginx \
                                                -c /etc/nginx/nginx.conf
nginx    32476 32475  0 13:36 ?        00:00:00  \_ nginx: worker process
nginx    32477 32475  0 13:36 ?        00:00:00  \_ nginx: worker process
nginx    32479 32475  0 13:36 ?        00:00:00  \_ nginx: worker process
nginx    32480 32475  0 13:36 ?        00:00:00  \_ nginx: worker process
nginx    32481 32475  0 13:36 ?        00:00:00  \_ nginx: cache manager process
nginx    32482 32475  0 13:36 ?        00:00:00  \_ nginx: cache loader process

在四核服务器,NGINX 主进程创建了4个工作进程和两个管理磁盘内容缓存的缓存辅助进程。

为什么架构很重要?

任何 Unix 应用程序的根本基础是线程或进程。(从 Linux 操作系统的角度来看,线程和进程大多是相同的,主要的区别是他们共享内存的程度。)一个线程或进程是一个自包含的指令集,操作系统可以在一个 CPU 核心上调度运行它们。大多数复杂的应用程序并行运行多个线程或进程有两个原因:

  • 它们可以同时使用更多的计算核心。
  • 线程或进程可以轻松实现并行操作。(例如,在同一时刻保持多连接)。

进程和线程消耗资源。他们每个都使用内存和其他系统资源,他们会在 CPU 核心中换入和换出(这个操作叫做上下文切换)。大多数现代服务器可以并行保持上百个小型的、活动的线程或进程,但是一旦内存耗尽或高 I/O 压力引起大量的上下文切换会导致性能严重下降。

网络应用程序设计的常用方法是为每个连接分配一个线程或进程。此体系结构简单、容易实现,但是当应用程序需要处理成千上万的并发连接时这种结构就不具备扩展性。

NGINX 如何工作?

NGINX 使用一种可预测的进程模式来分配可使用的硬件资源:

  • 主进程(master)执行特权操作,如读取配置和绑定端口,然后创建少量的子进程(如下的三种类型)。
  • 缓存加载器进程(cache loader)在加载磁盘缓存到内存中时开始运行,然后退出。适当的调度,所以其资源需求很低。
  • 缓存管理器进程(cache manager)定期裁剪磁盘缓存中的记录来保持他们在配置的大小之内。
  • 工作进程(worker)做所有的工作!他们保持网络连接、读写内容到磁盘,与上游服务器通信。

在大多数情况下 NGINX 的配置建议:每个 CPU 核心运行一个工作进程,这样最有效地利用硬件资源。你可以在配置中包含 worker\_processes auto指令配置:

worker_processes auto;

当一个 NGINX 服务处于活动状态,只有工作进程在忙碌。每个工作进程以非阻塞方式保持多连接,以减少上下文交换。

每个工作进程是一个单一线程并且独立运行,它们会获取新连接并处理之。这些进程可以使用共享内存通信来共享缓存数据、会话持久性数据及其它共享资源。(在 NGINX 1.7.11 及其以后版本,还有一个可选的线程池,工作进程可以转让阻塞的操作给它。更多的细节,参见“NGINX 线程池可以爆增9倍性能!”。对于 NGINX Plus 用户,该功能计划在今年晚些时候加入到 R7 版本中。)

NGINX 工作进程内部

每个 NGINX 工作进程按照 NGINX 配置初始化,并由主进程提供一组监听端口。

NGINX 工作进程首先在监听套接字上等待事件(accept\_mutex内核套接字分片)。事件被新进来的连接初始化。这些连接被分配到一个状态机 – HTTP 状态机是最常用的,但 NGINX 也实现了流式(原始 TCP )状态机和几种邮件协议(SMTP、IMAP和POP3)的状态机。

Internet Requests

状态机本质上是一组指令,告诉 NGINX 如何处理一个请求。大多数 web 服务器像 NGINX 一样使用类似的状态机来实现相同的功能 - 区别在于实现。

调度状态机

把状态机想象成国际象棋的规则。每个 HTTP 事务是一个象棋游戏。一方面棋盘是 web 服务器 —— 一位大师可以非常迅速地做出决定。另一方面是远程客户端 —— 在一个相对较慢的网络下 web 浏览器访问网站或应用程序。

不管怎样,这个游戏规则很复杂。例如,web 服务器可能需要与各方沟通(代理一个上游的应用程序)或与身份验证服务器对话。web 服务器的第三方模块甚至可以扩展游戏规则。

一个阻塞状态机

回忆我们之前的描述,一个进程或线程就像一套独立的指令集,操作系统可以在一个 CPU 核心上调度运行它。大多数 web 服务器和 web 应用使用每个连接一个进程或者每个连接一个线程的模式来玩这个“象棋游戏”。每个进程或线程都包含玩完“一个游戏”的指令。在服务器运行该进程的期间,其大部分的时间都是“阻塞的” —— 等待客户端完成它的下一步行动。

Blocking I/O

  1. web 服务器进程在监听套接字上监听新连接(客户端发起新“游戏”)
  2. 当它获得一个新游戏,就玩这个游戏,每走一步去等待客户端响应时就阻塞了。
  3. 游戏完成后,web 服务器进程可能会等待是否有客户机想要开始一个新游戏(这里指的是一个“保持的”连接)。如果这个连接关闭了(客户端断开或者发生超时),web 服务器进程会返回并监听一个新“游戏”。

要记住最重要的一点是每个活动的 HTTP 连接(每局棋)需要一个专用的进程或线程(象棋高手)。这个结构简单容并且易扩展第三方模块(“新规则”)。然而,还是有巨大的不平衡:尤其是轻量级 HTTP 连接其实就是一个文件描述符和小块内存,映射到一个单独的线程或进程,这是一个非常重量级的系统对象。这种方式易于编程,但太过浪费。

NGINX是一个真正的象棋大师

也许你听过车轮表演赛游戏,有一个象棋大师同时对战许多对手?

Kiril Georgiev

列夫·吉奥吉夫在保加利亚的索非亚同时对阵360人。他的最终成绩是284胜70平6负。

这就是 NGINX 工作进程如何“下棋”的。每个工作进程(记住 - 通常每个CPU核心上有一个工作进程)是一个可同时对战上百人(事实是,成百上千)的象棋大师。

Event-driven Architecture

  1. 工作进程在监听和连接套接字上等待事件。
  2. 事件发生在套接字上,并且由工作进程处理它们:

    • 在监听套接字的事件意味着一个客户端已经开始了一局新棋局。工作进程创建了一个新连接套接字。
    • 在连接套接字的事件意味着客户端已经下了一步棋。工作进程及时响应。

一个工作进程在网络流量上从不阻塞,等待它的“对手”(客户端)做出反应。当它下了一步,工作进程立即继续其他的游戏,在那里工作进程正在处理下一步,或者在门口欢迎一个新玩家。

为什么这个比阻塞式多进程架构更快?

NGINX 每个工作进程很好的扩展支撑了成百上千的连接。每个连接在工作进程中创建另外一个文件描述符和消耗一小部分额外内存。每个连接有很少的额外开销。NGINX 进程可以固定在某个 CPU 上。上下文交换非常罕见,一般只发生在没有工作要做时。

在阻塞方式,每个进程一个连接的方法中,每个连接需要大量额外的资源和开销,并且上下文切换(从一个进程切换到另一个)非常频繁。

更详细的解释,看看这篇关于 NGINX 架构的文章,它由NGINX公司开发副总裁及共同创始人 Andrew Alexeev 写的。

通过适当的系统优化,NGINX 的每个工作进程可以扩展来处理成千上万的并发 HTTP 连接,并能脸不红心不跳的承受峰值流量(大量涌入的新“游戏”)。

更新配置和升级 NGINX

NGINX 的进程体系架构使用少量的工作进程,有助于有效的更新配置文件甚至 NGINX 程序本身。

Updating Configuration

更新 NGINX 配置文件是非常简单、轻量、可靠的操作。典型的就是运行命令 nginx –s reload,所做的就是检查磁盘上的配置并发送 SIGHUP 信号给主进程。

当主进程接收到一个 SIGHUP 信号,它会做两件事:

  • 重载配置文件和分支出一组新的工作进程。这些新的工作进程立即开始接受连接和处理流量(使用新的配置设置)
  • 通知旧的工作进程优雅的退出。工作进程停止接受新的连接。当前的 http 请求一旦完成,工作进程就彻底关闭这个连接(那就是,没有残存的“保持”连接)。一旦所有连接关闭,这个工作进程就退出。

这个重载过程能引发一个 CPU 和内存使用的小峰值,但是跟活动连接加载的资源相比它一般不易察觉。每秒钟你可以多次重载配置(很多 NGINX 用户都这么做)。非常罕见的情况下,有很多世代的工作进程等待关闭连接时会发生问题,但即使是那样也很快被解决了。

NGINX 的程序升级过程中拿到了高可用性圣杯 —— 你可以随时更新这个软件,不会丢失连接,停机,或者中断服务。

New Binary

程序升级过程类似于平滑重载配置的方法。一个新的 NGINX 主进程与原主进程并行运行,然后他们共享监听套接字。两个进程都是活动的,并且各自的工作进程处理流量。然后你可以通知旧的主进程和它的工作进程优雅的退出。

整个过程的详细描述在 NGINX 管理

结论

深入 NGINX 信息图提供一个 NGINX 功能实现的高层面概览,但在这简单的解释的背后是超过十年的创新和优化,使得 NGINX 在广泛的硬件上提供尽可能最好的性能同时保持了现代 Web 应用程序所需要的安全性和可靠性。

如果你想阅读更多关于NGINX的优化,查看这些优秀的资源:


via: http://nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/

作者:Owen Garrett 译者:wyangsun 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

问题: 我注意到有一些机器人经常访问我的nginx驱动的网站,并且进行一些攻击性的扫描,导致消耗掉了我的网络服务器的大量资源。我一直尝试着通过用户代理符串来阻挡这些机器人。我怎样才能在nginx网络服务器上阻挡掉特定的用户代理呢?

现代互联网滋生了大量各种各样的恶意机器人和网络爬虫,比如像恶意软件机器人、垃圾邮件程序或内容刮刀,这些恶意工具一直偷偷摸摸地扫描你的网站,干些诸如检测潜在网站漏洞、收获电子邮件地址,或者只是从你的网站偷取内容。大多数机器人能够通过它们的“用户代理”签名字符串来识别。

作为第一道防线,你可以尝试通过将这些机器人的用户代理字符串添加入robots.txt文件来阻止这些恶意软件机器人访问你的网站。但是,很不幸的是,该操作只针对那些“行为良好”的机器人,这些机器人被设计遵循robots.txt的规范。许多恶意软件机器人可以很容易地忽略掉robots.txt,然后随意扫描你的网站。

另一个用以阻挡特定机器人的途径,就是配置你的网络服务器,通过特定的用户代理字符串拒绝要求提供内容的请求。本文就是说明如何在nginx网络服务器上阻挡特定的用户代理

在Nginx中将特定用户代理列入黑名单

要配置用户代理阻挡列表,请打开你的网站的nginx配置文件,找到server定义部分。该文件可能会放在不同的地方,这取决于你的nginx配置或Linux版本(如,/etc/nginx/nginx.conf,/etc/nginx/sites-enabled/<your-site>,/usr/local/nginx/conf/nginx.conf,/etc/nginx/conf.d/<your-site>)。

server {
    listen       80 default_server;
    server_name  xmodulo.com;
    root         /usr/share/nginx/html;

    ....
}

在打开该配置文件并找到 server 部分后,添加以下 if 声明到该部分内的某个地方。

server {
    listen       80 default_server;
    server_name  xmodulo.com;
    root         /usr/share/nginx/html;

    # 大小写敏感的匹配
    if ($http_user_agent ~ (Antivirx|Arian) {
        return 403;
    }

    #大小写无关的匹配
    if ($http_user_agent ~* (netcrawl|npbot|malicious)) {
        return 403;
    }

    ....
}

如你所想,这些 if 声明使用正则表达式匹配了任意不良用户字符串,并向匹配的对象返回403 HTTP状态码。 $http_user_agent是HTTP请求中的一个包含有用户代理字符串的变量。‘~’操作符针对用户代理字符串进行大小写敏感匹配,而‘~*’操作符则进行大小写无关匹配。‘|’操作符是逻辑或,因此,你可以在 if 声明中放入众多的用户代理关键字,然后将它们全部阻挡掉。

在修改配置文件后,你必须重新加载nginx以激活阻挡:

$ sudo /path/to/nginx -s reload

你可以通过使用带有 “--user-agent” 选项的 wget 测试用户代理阻挡。

$ wget --user-agent "malicious bot" http://<nginx-ip-address>

管理Nginx中的用户代理黑名单

目前为止,我已经展示了在nginx中如何阻挡一些用户代理的HTTP请求。如果你有许多不同类型的网络爬虫机器人要阻挡,又该怎么办呢?

由于用户代理黑名单会增长得很大,所以将它们放在nginx的server部分不是个好点子。取而代之的是,你可以创建一个独立的文件,在该文件中列出所有被阻挡的用户代理。例如,让我们创建/etc/nginx/useragent.rules,并定义以下面的格式定义所有被阻挡的用户代理的图谱。

$ sudo vi /etc/nginx/useragent.rules

map $http_user_agent $badagent {
        default         0;
        ~*malicious     1;
        ~*backdoor      1;
        ~*netcrawler    1;
        ~Antivirx       1;
        ~Arian          1;
        ~webbandit      1;
}

与先前的配置类似,‘~*’将匹配以大小写不敏感的方式匹配关键字,而‘~’将使用大小写敏感的正则表达式匹配关键字。“default 0”行所表达的意思是,任何其它文件中未被列出的用户代理将被允许。

接下来,打开你的网站的nginx配置文件,找到里面包含 http 的部分,然后添加以下行到 http 部分某个位置。

http {
    .....
    include /etc/nginx/useragent.rules
}

注意,该 include 声明必须出现在 server 部分之前(这就是为什么我们将它添加到了 http 部分里)。

现在,打开nginx配置定义你的服务器的部分,添加以下 if 声明:

server {
    ....

    if ($badagent) {
        return 403;
    }

    ....
}

最后,重新加载nginx。

$ sudo /path/to/nginx -s reload

现在,任何包含有/etc/nginx/useragent.rules中列出的关键字的用户代理将被nginx自动禁止。


via: http://ask.xmodulo.com/block-specific-user-agents-nginx-web-server.html

作者:Dan Nanni 译者:GOLinux 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

本文向你介绍如何在 nginx 服务器上设置健壮的 SSL 安全机制。我们通过禁用 SSL 压缩来降低 CRIME 攻击威胁;禁用协议上存在安全缺陷的 SSLv3 及更低版本,并设置更健壮的 加密套件 cipher suite 来尽可能启用 前向安全性 Forward Secrecy ;此外,我们还启用了 HSTS 和 HPKP。这样我们就拥有了一个健壮而可经受考验的 SSL 配置,并可以在 Qually Labs 的 SSL 测试中得到 A 级评分。

如果不求甚解的话,可以从 https://cipherli.st 上找到 nginx 、Apache 和 Lighttpd 的安全设置,复制粘帖即可。

本教程在 Digital Ocean 的 VPS 上测试通过。如果你喜欢这篇教程,想要支持作者的站点的话,购买 Digital Ocean 的 VPS 时请使用如下链接:https://www.digitalocean.com/?refcode=7435ae6b8212

本教程可以通过发布于 2014/1/21 的 SSL 实验室测试的严格要求(我之前就通过了测试,如果你按照本文操作就可以得到一个 A+ 评分)。

你可以从下列链接中找到这方面的进一步内容:

我们需要编辑 nginx 的配置,在 Ubuntu/Debian 上是 /etc/nginx/sited-enabled/yoursite.com,在 RHEL/CentOS 上是 /etc/nginx/conf.d/nginx.conf

本文中,我们需要编辑443端口(SSL)的 server 配置中的部分。在文末你可以看到完整的配置例子。

在编辑之前切记备份一下配置文件!

野兽攻击(BEAST)和 RC4

简单的说, 野兽攻击 BEAST 就是通过篡改一个加密算法的 密码块链 CBC,cipher block chaining 的模式,从而可以对部分编码流量悄悄解码。更多信息参照上面的链接。

针对 野兽攻击 BEAST ,较新的浏览器已经启用了客户端缓解方案。推荐方案是禁用 TLS 1.0 的所有加密算法,仅允许 RC4 算法。然而,针对 RC4 算法的攻击也越来越多 ,很多已经从理论上逐步发展为实际可行的攻击方式。此外,有理由相信 NSA 已经实现了他们所谓的“大突破”——攻破 RC4 。

禁用 RC4 会有几个后果。其一,当用户使用老旧的浏览器时,比如 Windows XP 上的 IE 会用 3DES 来替代 RC4。3DES 要比 RC4 更安全,但是它的计算成本更高,你的服务器就需要为这些用户付出更多的处理成本。其二,RC4 算法能减轻 野兽攻击 BEAST 的危害,如果禁用 RC4 会导致 TLS 1.0 用户会换到更容易受攻击的 AES-CBC 算法上(通常服务器端的对 野兽攻击 BEAST 的“修复方法”是让 RC4 优先于其它算法)。我认为 RC4 的风险要高于 野兽攻击 BEAST 的风险。事实上,有了客户端缓解方案(Chrome 和 Firefox 提供了缓解方案), 野兽攻击 BEAST 就不是什么大问题了。而 RC4 的风险却在增长:随着时间推移,对加密算法的破解会越来越多。

怪物攻击(FREAK)

怪物攻击 FREAK 是一种中间人攻击,它是由来自 INRIA、微软研究院和 IMDEA 的密码学家们所发现的。 怪物攻击 FREAK 的缩写来自“ RSA 出口密钥因子分解 Factoring RSA-EXPORT Keys

这个漏洞可上溯到上世纪九十年代,当时美国政府禁止出口加密软件,除非其使用编码密钥长度不超过512位的出口加密套件。

这造成了一些现在的 TLS 客户端存在一个缺陷,这些客户端包括: 苹果的 SecureTransport 、OpenSSL。这个缺陷会导致它们会接受出口降级 RSA 密钥,即便客户端并没有要求使用出口降级 RSA 密钥。这个缺陷带来的影响很讨厌:在客户端存在缺陷,且服务器支持出口降级 RSA 密钥时,会发生中间人攻击,从而导致连接的强度降低。

攻击分为两个组成部分:首先是服务器必须接受“ 出口降级 RSA 密钥 export grade RSA ”。

中间人攻击可以按如下流程:

  • 在客户端的 Hello 消息中,要求标准的 RSA 加密套件。
  • 中间人攻击者修改该消息为 ‘输出级 RSA 密钥’ export RSA
  • 服务器回应一个512位的输出级 RSA 密钥,并以其长期密钥签名。
  • 由于 OpenSSL/SecureTransport 的缺陷,客户端会接受这个弱密钥。
  • 攻击者根据 RSA 模数分解因子来恢复相应的 RSA 解密密钥。
  • 当客户端编码 ‘预主密码’ pre-master secret 给服务器时,攻击者现在就可以解码它并恢复 TLS 的 ‘主密码’ master secret
  • 从这里开始,攻击者就能看到了传输的明文并注入任何东西了。

本文所提供的加密套件不启用输出降级加密,请确认你的 OpenSSL 是最新的,也强烈建议你将客户端也升级到新的版本。

心血漏洞(Heartbleed)

心血漏洞 Heartbleed 是一个于2014年4月公布的 OpenSSL 加密库的漏洞,它是一个被广泛使用的传输层安全(TLS)协议的实现。无论是服务器端还是客户端在 TLS 中使用了有缺陷的 OpenSSL,都可以被利用该缺陷。由于它是因 DTLS 心跳扩展(RFC 6520)中的输入验证不正确(缺少了边界检查)而导致的,所以该漏洞根据“心跳”而命名。这个漏洞是一种缓存区超读漏洞,它可以读取到本不应该读取的数据。

哪个版本的 OpenSSL 受到 心血漏洞 Heartbleed 的影响?

各版本情况如下:

  • OpenSSL 1.0.1 直到 1.0.1f (包括)存在该缺陷
  • OpenSSL 1.0.1g 没有该缺陷
  • OpenSSL 1.0.0 分支没有该缺陷
  • OpenSSL 0.9.8 分支没有该缺陷

这个缺陷是2011年12月引入到 OpenSSL 中的,并随着 2012年3月14日 OpenSSL 发布的 1.0.1 而泛滥。2014年4月7日发布的 OpenSSL 1.0.1g 修复了该漏洞。

升级你的 OpenSSL 就可以避免该缺陷。

SSL 压缩(罪恶攻击 CRIME)

罪恶攻击 CRIME 使用 SSL 压缩来完成它的魔法,SSL 压缩在下述版本是默认关闭的: nginx 1.1.6及更高/1.0.9及更高(如果使用了 OpenSSL 1.0.0及更高), nginx 1.3.2及更高/1.2.2及更高(如果使用较旧版本的 OpenSSL)。

如果你使用一个早期版本的 nginx 或 OpenSSL,而且你的发行版没有向后移植该选项,那么你需要重新编译没有一个 ZLIB 支持的 OpenSSL。这会禁止 OpenSSL 使用 DEFLATE 压缩方式。如果你禁用了这个,你仍然可以使用常规的 HTML DEFLATE 压缩。

SSLv2 和 SSLv3

SSLv2 是不安全的,所以我们需要禁用它。我们也禁用 SSLv3,因为 TLS 1.0 在遭受到降级攻击时,会允许攻击者强制连接使用 SSLv3,从而禁用了 前向安全性 forward secrecy

如下编辑配置文件:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

卷毛狗攻击(POODLE)和 TLS-FALLBACK-SCSV

SSLv3 会受到卷毛狗漏洞(POODLE)的攻击。这是禁用 SSLv3 的主要原因之一。

Google 提出了一个名为 TLS\_FALLBACK\_SCSV 的SSL/TLS 扩展,它用于防止强制 SSL 降级。如果你升级 到下述的 OpenSSL 版本会自动启用它。

  • OpenSSL 1.0.1 带有 TLS\_FALLBACK\_SCSV 1.0.1j 及更高。
  • OpenSSL 1.0.0 带有 TLS\_FALLBACK\_SCSV 1.0.0o 及更高。
  • OpenSSL 0.9.8 带有 TLS\_FALLBACK\_SCSV 0.9.8zc 及更高。

更多信息请参照 NGINX 文档

加密套件(cipher suite)

前向安全性 Forward Secrecy 用于在长期密钥被破解时确保会话密钥的完整性。 完备的前向安全性 PFS,Perfect Forward Secrecy 是指强制在每个/每次会话中推导新的密钥。

这就是说,泄露的私钥并不能用来解密(之前)记录下来的 SSL 通讯。

提供 完备的前向安全性 PFS,Perfect Forward Secrecy 功能的是那些使用了一种 Diffie-Hellman 密钥交换的短暂形式的加密套件。它们的缺点是系统开销较大,不过可以使用椭圆曲线的变体来改进。

以下两个加密套件是我推荐的,之后Mozilla 基金会也推荐了。

推荐的加密套件:

ssl_ciphers 'AES128+EECDH:AES128+EDH';

向后兼容的推荐的加密套件(IE6/WinXP):

ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

如果你的 OpenSSL 版本比较旧,不可用的加密算法会自动丢弃。应该一直使用上述的完整套件,让 OpenSSL 选择一个它所支持的。

加密套件的顺序是非常重要的,因为其决定了优先选择哪个算法。上述优先推荐的算法中提供了PFS(完备的前向安全性)。

较旧版本的 OpenSSL 也许不能支持这个算法的完整列表,AES-GCM 和一些 ECDHE 算法是相当新的,在 Ubuntu 和 RHEL 中所带的绝大多数 OpenSSL 版本中不支持。

优先顺序的逻辑

  • ECDHE+AESGCM 加密是首选的。它们是 TLS 1.2 加密算法,现在还没有广泛支持。当前还没有对它们的已知攻击。
  • PFS 加密套件好一些,首选 ECDHE,然后是 DHE。
  • AES 128 要好于 AES 256。有一个关于 AES256 带来的安全提升程度是否值回成本的讨论,结果是显而易见的。目前,AES128 要更值一些,因为它提供了不错的安全水准,确实很快,而且看起来对时序攻击更有抵抗力。
  • 在向后兼容的加密套件里面,AES 要优于 3DES。在 TLS 1.1及其以上,减轻了针对 AES 的 野兽攻击 BEAST 的威胁,而在 TLS 1.0上则难以实现该攻击。在非向后兼容的加密套件里面,不支持 3DES。
  • RC4 整个不支持了。3DES 用于向后兼容。参看 #RC4\_weaknesses 中的讨论。

强制丢弃的算法

  • aNULL 包含了非验证的 Diffie-Hellman 密钥交换,这会受到 中间人 MITM 攻击
  • eNULL 包含了无加密的算法(明文)
  • EXPORT 是老旧的弱加密算法,是被美国法律标示为可出口的
  • RC4 包含的加密算法使用了已弃用的 ARCFOUR 算法
  • DES 包含的加密算法使用了弃用的数据加密标准(DES)
  • SSLv2 包含了定义在旧版本 SSL 标准中的所有算法,现已弃用
  • MD5 包含了使用已弃用的 MD5 作为哈希算法的所有算法

更多设置

确保你也添加了如下行:

ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;

在一个 SSLv3 或 TLSv1 握手过程中选择一个加密算法时,一般使用客户端的首选算法。如果设置了上述配置,则会替代地使用服务器端的首选算法。

前向安全性和 Diffie Hellman Ephemeral (DHE)参数

前向安全性 Forward Secrecy 的概念很简单:客户端和服务器协商一个永不重用的密钥,并在会话结束时销毁它。服务器上的 RSA 私钥用于客户端和服务器之间的 Diffie-Hellman 密钥交换签名。从 Diffie-Hellman 握手中获取的预主密钥会用于之后的编码。因为预主密钥是特定于客户端和服务器之间建立的某个连接,并且只用在一个限定的时间内,所以称作 短暂模式 Ephemeral

使用了前向安全性,如果一个攻击者取得了一个服务器的私钥,他是不能解码之前的通讯信息的。这个私钥仅用于 Diffie Hellman 握手签名,并不会泄露预主密钥。Diffie Hellman 算法会确保预主密钥绝不会离开客户端和服务器,而且不能被中间人攻击所拦截。

所有版本的 nginx(如1.4.4)都依赖于 OpenSSL 给 Diffie-Hellman (DH)的输入参数。不幸的是,这意味着 Diffie-Hellman Ephemeral(DHE)将使用 OpenSSL 的默认设置,包括一个用于密钥交换的1024位密钥。因为我们正在使用2048位证书,DHE 客户端就会使用一个要比非 DHE 客户端更弱的密钥交换。

我们需要生成一个更强壮的 DHE 参数:

cd /etc/ssl/certs
openssl dhparam -out dhparam.pem 4096

然后告诉 nginx 将其用作 DHE 密钥交换:

ssl_dhparam /etc/ssl/certs/dhparam.pem;

OCSP 装订(Stapling)

当连接到一个服务器时,客户端应该使用 证书吊销列表 CRL,Certificate Revocation List 在线证书状态协议 OCSP,Online Certificate Status Protocol 记录来校验服务器证书的有效性。CRL 的问题是它已经增长的太大了,永远也下载不完了。

OCSP 更轻量级一些,因为我们每次只请求一条记录。但是副作用是当连接到一个服务器时必须对第三方 OCSP 响应器发起 OCSP 请求,这就增加了延迟和带来了潜在隐患。事实上,CA 所运营的 OCSP 响应器非常不可靠,浏览器如果不能及时收到答复,就会静默失败。攻击者通过 DoS 攻击一个 OCSP 响应器可以禁用其校验功能,这样就降低了安全性。

解决方法是允许服务器在 TLS 握手中发送缓存的 OCSP 记录,以绕开 OCSP 响应器。这个机制节省了客户端和 OCSP 响应器之间的通讯,称作 OCSP 装订。

客户端会在它的 CLIENT HELLO 中告知其支持 status\_request TLS 扩展,服务器仅在客户端请求它的时候才发送缓存的 OCSP 响应。

大多数服务器最多会缓存 OCSP 响应48小时。服务器会按照常规的间隔连接到 CA 的 OCSP 响应器来获取刷新的 OCSP 记录。OCSP 响应器的位置可以从签名的证书中的 授权信息访问 Authority Information Access 字段中获得。

HTTP 严格传输安全(HSTS)

如有可能,你应该启用 HTTP 严格传输安全(HSTS),它会引导浏览器和你的站点之间的通讯仅通过 HTTPS。

HTTP 公钥固定扩展(HPKP)

你也应该启用 HTTP 公钥固定扩展(HPKP)

公钥固定的意思是一个证书链必须包括一个白名单中的公钥。它确保仅有白名单中的 CA 才能够为某个域名签署证书,而不是你的浏览器中存储的任何 CA。

我已经写了一篇关于 HPKP 的背景理论及在 Apache、Lighttpd 和 NGINX 中配置例子的文章

配置范例

server {

  listen [::]:443 default_server;

  ssl on;
  ssl_certificate_key /etc/ssl/cert/raymii_org.pem;
  ssl_certificate /etc/ssl/cert/ca-bundle.pem;

  ssl_ciphers 'AES128+EECDH:AES128+EDH:!aNULL';

  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_session_cache shared:SSL:10m;

  ssl_stapling on;
  ssl_stapling_verify on;
  resolver 8.8.4.4 8.8.8.8 valid=300s;
  resolver_timeout 10s;

  ssl_prefer_server_ciphers on;
  ssl_dhparam /etc/ssl/certs/dhparam.pem;

  add_header Strict-Transport-Security max-age=63072000;
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;

  root /var/www/;
  index index.html index.htm;
  server_name raymii.org;

}

结尾

如果你使用了上述配置,你需要重启 nginx:

# 首先检查配置文件是否正确
/etc/init.d/nginx configtest
# 然后重启
/etc/init.d/nginx restart

现在使用 SSL Labs 测试来看看你是否能得到一个漂亮的“A”。当然了,你也得到了一个安全的、强壮的、经得起考验的 SSL 配置!


via: https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html

作者:Remy van Elst 译者:wxy 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

通常,大多数默认设置安装的web服务器存在信息泄露,这其中之一就是PHP。PHP 是如今流行的服务端html嵌入式语言(之一?)。在如今这个充满挑战的时代,有许多攻击者会尝试发现你服务端的漏洞。因此,我会简单描述如何在Linux服务器中隐藏PHP信息。

默认上expose\_php默认是开的。关闭“expose\_php”参数可以使php隐藏它的版本信息。

[root@centos66 ~]# vi /etc/php.ini

在你的php.ini, 定位到含有expose\_php的那行把On设成Off:

expose_php = Off

在此之前,web服务器头看上去就像这样:

[root@centos66 ~]# curl -I http://www.ehowstuff.com/

HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html; charset=UTF-8
Vary: Accept-Encoding
X-Powered-By: PHP/5.3.3
X-Pingback: http://www.ehowstuff.com/xmlrpc.php
Date: Wed, 11 Feb 2015 14:10:43 GMT
X-Page-Speed: 1.9.32.2-4321
Cache-Control: max-age=0, no-cache

更改并重启 Web 服务后,php就不会在web服务头中显示版本了:

HTTP/1.1 200 OK
Server: nginx
Date: Wed, 11 Feb 2015 15:38:14 GMT
Content-Type: text/html; charset=UTF-8
Vary: Accept-Encoding
X-Pingback: http://www.ehowstuff.com/xmlrpc.php
Date: Wed, 11 Feb 2015 14:10:43 GMT
X-Page-Speed: 1.9.32.2-4321
Cache-Control: max-age=0, no-cache

LCTT译注:除了 PHP 的版本之外,Web 服务器也会默认泄露版本号。如果使用 Apache 服务器,请参照此文章关闭Apache 版本显示;如果使用 Nginx 服务器,请在 http 段内加入server_tokens off; 配置。以上修改请记得重启相关服务。


via: http://www.ehowstuff.com/how-to-hide-php-version-in-linux/

作者:skytech 译者:geekpi 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

用户应该更新他们的系统来修复这个漏洞!


Canonical已经在安全公告中公布了这个影响到Ubuntu 14.04 LTS (Trusty Tahr)的nginx漏洞的细节。这个问题已经被确定并被修复了

Ubuntu的开发者已经修复了nginx的一个小漏洞。他们解释nginx可能已经被利用来暴露网络上的敏感信息。

根据安全公告,“Antoine Delignat-Lavaud和Karthikeyan Bhargavan发现nginx错误地重复使用了缓存的SSL会话。攻击者可能利用此问题,在特定的配置下,可以从不同的虚拟主机获得信息“。

对于这些问题的更详细的描述,可以看到Canonical的安全公告。用户应该升级自己的Linux发行版以解决此问题。

这个问题可以通过在系统升级到最新nginx包(和依赖v包)进行修复。要应用该补丁,你可以直接运行升级管理程序。

如果你不想使用软件更新器,您可以打开终端,输入以下命令(需要root权限):

sudo apt-get update
sudo apt-get dist-upgrade

在一般情况下,一个标准的系统更新将会进行必要的更改。要应用此修补程序您不必重新启动计算机。


via: http://news.softpedia.com/news/Canonical-Closes-Nginx-Exploit-in-Ubuntu-14-04-LTS-459677.shtml

作者:Silviu Stahie 译者:geekpi 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

在我的上一篇文章中讲过如何做一个高可用系统:两个树莓派布署上 GlusterFS 集群文件系统,就变成一个容错文件服务器了。在这篇文章中我们会基于这个高可用系统构建另一个容错服务:建立一个简单的 Web 服务器集群。

可能你没有看过我的上一篇文章,那我就在这里简单回顾一下上次的内容。我有两个树莓派:Pi1 和 Pi2。Pi1 的 IP 地址为 192.168.0.121,Pi2 的 IP 地址为 192.168.0.122。我把它们组合成为 GlusterFS 集群系统,共享一个存储卷,卷名为 gv0。并且这个 gv0 被挂载在两个树莓派上,挂载点都是 /mnt/gluster1,这样一来,两个树莓派能同时访问到这个共享卷。最后我测试了下系统的容错性,将共享卷挂载到第三个物理机上,并执行共享卷上的一个简单的脚本:打印系统时间并输出到 gv0 上的一个文件内,然后轮着关掉两台树莓派,检测这个冗余系统是否还能用。

现在我手上有这个经过检验的存储系统,我要做的是把这个系统做成有容错功能的 Web 服务器集群。树莓派的 CPU 处理速度和内存资源都不是很高,好在对付一个静态 Web 服务器已经是绰绰有余了。我故意把这个例子做得非常简单,因为我觉得如果你能摆平这个简单的例子,你也能处理复杂一点的问题了。

安装 Nginx

虽然我也比较喜欢 Apache,但在资源有限的情况下,像 Nginx 这样功能全、性能高、资源占用少的 Web 服务器是比较理想的选择。在 Raspbian 的默认源中存在 Nginx,所以我只要登入一台树莓派并且输入以下命令:

$ sudo apt-get update
$ sudo apt-get install nginx

Nginx 安装好后,创建配置文件 /mnt/gluster1/cluster ,内容如下:

server {
  root /mnt/gluster1/www;
  index index.html index.htm;
  server_name twopir twopir.example.com;

  location / {
        try_files $uri $uri/ /index.html;
  }
}

注意:我这里把服务器命名为“twopir”,你可以根据自己爱好命名你的网站。另外我把 Web 服务器的根目录设置为 /mng/gluster1/www。这样,我就能把我的静态文件放在这个共享存储系统内,从而让两个树莓派主机都访问到它们。

现在删除默认的 Nginx 配置文件,将上面配好的配置文件作为 Nginx 的配置文件。在 Debian 系统中,Nginx 将它的配置文件像 Apache 一样放在 sites-available 和 site-enabled 两个目录下面。虚拟主机配置文档放在 sites-available 中,而 sites-enabled 目录包含了你想生效的配置文件的软链接。

$ cd /etc/nginx/sites-available
$ sudo ln -s /mnt/gluster1/cluster .
$ cd /etc/nginx/sites-enabled
$ sudo rm default
$ sudo ln -s /etc/nginx/sites-available/cluster .

现在我已经放好了配置文件,但系统还不存在上面所说的 Web 服务器根目录。下一步就是创建目录 /mnt/gluster1/www,并复制 index.html 文件进去。当然你也可以建立自己定义的 index.html 文件,但先复制一个已有的文件是个不错的选择:

$ sudo mkdir /mnt/gluster1/www
$ cp /usr/share/nginx/www/index.html /mnt/gluster1/www

重启 Nginx 服务:

$ sudo /etc/init.d/nginx restart

现在去 DNS 服务器为192.168.0.121的树莓派配置记录。你可以根据自己的情况配置你自己的域名和 IP 地址。现在在浏览器上输入 http://twopir/ 然后出现默认的 Nginx 首页。如果你查看下 /var/log/nginx/access.log 文件,你可以看到点击网页留下的记录。

Nginx 能正常工作后,配置第二个树莓派。因为我们已经将配置文件都放在 GlusterFS 共享目录下,我们现在要做的只是安装 Nginx,创建相关的软链接,重启 Nginx:

$ sudo apt-get update
$ sudo apt-get install nginx
$ cd /etc/nginx/sites-available
$ sudo ln -s /mnt/gluster1/cluster .
$ cd /etc/nginx/sites-enabled
$ sudo rm default
$ sudo ln -s /etc/nginx/sites-available/cluster .
$ sudo /etc/init.d/nginx restart

DNS 服务器上配置两条 A 记录

现在两个主机共享同一份文件,下一步是设置冗余系统的关键步骤。虽然你完全可以设置一个类似心跳的服务用于轮询检测哪个树莓派的 Web 服务是开启的,但这里有个更好的方法:给同一个主机名指定两个 DNS 的 A 记录,分别指向你的两个树莓派(译注:A 记录就是将域名转化为 IP 地址的记录,DNS 包含很多记录方式,如 A 记录、PTR 记录、MX 记录等等),这就是传说中的 DNS 负载均衡,DNS 访问主机时,如果主机名对应多个 IP 地址,DNS 会随机返回这些 IP 地址的顺序:

$ dig twopir.example.com A +short
192.168.0.121
192.168.0.122
$ dig twopir.example.com A +short
192.168.0.122
192.168.0.121

因为返回随机的顺序,用户可以均匀地往两台服务器发送请求,这个负载均衡的机制就是由 DNS 服务器的多条 A 记录来提供。相对于 DNS 的负载均衡技术,我更感兴趣的是 Web 浏览器如何处理请求失败的情况。当浏览器通过网页主机获得两条 A 记录,并且第一条记录所在的主机当机了,浏览器几乎立刻就切到另一条记录上。切换效率快到用户根本察觉不出来,这可比传统的心跳线轮循请求主机快多了。

所以在你正在使用的 DNS 服务器上添加你的树莓派集群的两个 IP 地址,然后试试 dig 命令,就像我在上面使用过的一样,你也应该能得到两个 IP 地址。

当你为同一个域名设置好了两个 A 记录,这套集群就可以提供容错服务了。打开两个终端并分别登录到两个树莓派,运行 tail -f /var/log/ngnix/access.log 命令,你可以监视 Web 服务器的访问情况。当你通过浏览器访问网页时,你可以看到在一台树莓派上产生了访问日志,而在另外一台的日志里什么也没有出现。现在你可以刷新几次页面,当你觉得你对能成功访问到 Web 服务器感到满意了,你可以重启响应你请求的那台树莓派,然后再刷新几次页面。也许浏览器上会出现一个短暂的不可访问信号,但会马上重定向到第二台树莓派上,你会看到一样的页面,并且你能通过终端访问日志了解具体情况。当第一台树莓派启动后,你在浏览器上根本不会察觉到。

(译注:如何处理DNS 轮询的多个IP地址,不同浏览器有不同的做法,目前译者收集到的资料显示,只有mozilla的netlib库支持自动重连下一个IP地址的做法。如果读者知道更多的浏览器对DNS轮询的处理策略,请评论给我们。其实,以译者的态度看,DNS轮询根本就不能算作是高可用性的方案,勉强可以算作是负载均衡方案,建议考虑更可靠的其它方案。)

随机重启一台树莓派,只要有一台在线,Web 服务器就能提供服务。这是一个非常简单的案例,你可以把你其它的静态文件放到 /mnt/gluster1/www 上,为你提供真正有价值的服务,现在好好享受你的低成本容错集群 Web 服务器吧。


via: http://www.linuxjournal.com/content/two-pi-r-2-web-servers

译者:bazz2 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出