NGINX Plus R26 正式发布

NGINX | 2022年2月15日

我们很高兴地宣布,NGINX Plus Release 26(R26)现已发布。NGINX Plus基于NGINX Open Source构建,是一款集软件Web服务器、负载均衡器、反向代理、内容缓存和API网关于一体的解决方案。

NGINX Plus R26 的新增和增强功能包括:

  • 通过缓存JSON Web密钥集加快JWT验证,在过去几个版本持续增强JSON Web令牌(JWT)支持的基础上,我们引入了JSON Web密钥集(JWKS)的内存缓存,可显著降低JWT验证的开销。
  • 强化的TLS握手:如果客户端通过ALPN提议的通信协议与待建立会话的NGINX配置上下文不匹配,NGINX Plus将拒绝TLS握手(例如,向http{}上下文中的虚拟服务器提议使用IMAP电子邮件协议)。
  • NGINX JavaScript 模块增强功能:现在支持使用 async 和 await 关键字及 Promise 对象的异步函数,并已实现用于加密操作(例如生成随机数或加密 Cookie)的 WebCrypto API。

本次版本还新增了对IBM System Z (s390x)架构的支持、独立关闭TCP连接各方向的功能,以及对Perl兼容正则表达式(PCRE)库第2版的支持。

重要行为变更

NGINX JavaScript模块不再支持js_include

正如发布NGINX Plus R23时所宣布的,NGINX JavaScript模块的0.4.0版本使用js_import指令取代了js_include指令。js_include指令当时已弃用,自此版本起不再受支持。

升级到NGINX Plus R26之前,请将NGINX配置文件中的js_include替换为js_import,并在JavaScript文件中为NGINX配置所引用的函数添加export语句。请按以下步骤操作:

  1. 编辑NGINX配置文件。例如,将以下内容:
js_set $foo myFunction;
  1. 更改为:
js_set $foo module_name.myFunction;
  • 将js_include替换为js_import,并记下隐式的module_name(传递给该指令的JavaScript文件名参数,不含​.js扩展名)。
  • 在每个引用JavaScript函数的指令中,在函数名称前添加module_name。函数名称是这些指令的第一个参数;对于js_set[HTTP][Stream]指令,函数名称是第二个参数。
  1. 编辑定义了NGINX配置文件中所引用函数的JavaScript(module_name.js)文件。在每个文件中添加如下所示的export语句,并列出所引用的函数。
export default { myFunction, otherFunction }
  1. The export语句可以出现在.js文件中的任何位置,但通常放在函数的正上方或文件末尾。

Cookie-Flag模块已弃用

第三方Cookie‑Flag模块已在NGINX Plus R23中弃用,并且正如当时所公告的那样,自此版本起,该模块已无法再从NGINX模块存储库中获取。

升级到NGINX Plus R26之前,请编辑NGINX配置,将所有出现的“set_cookie_flag”指令(在已弃用的模块中定义)替换为内置的“proxy_cookie_flags”指令。

TLS协商不再支持NPN协议

NGINX建立TLS和HTTP/2连接的方式已更新。在NGINX与客户端(通常为浏览器)进行TLS握手时,双方会协商该握手所建立的会话要使用的通信协议(多数情况下,协商会将会话从HTTP 1.x升级到HTTP/2)。TLS的下一协议协商(NPN)扩展是最早用于此目的的方法,但NPN现已被视为过时,并由应用层协议协商(ALPN)扩展取代。该扩展发布为RFC 7301。

NGINX Plus R26不再支持NPN,因此客户端现在必须仅使用ALPN。

此外,我们扩展并强化了ALPN实现,详情请参阅“强化TLS握手”。

旧版NGINX Plus软件仓库不再更新

在NGINX Plus R24发布时,所有NGINX软件的程序包存储库均进行了重组,因此NGINX Plus的安装流程也随之发生变化。

安装或升级NGINX Plus时,操作系统的软件包管理器(apt、yum或同等工具)将配置为使用NGINX Plus软件仓库。

如果要在已配置为使用旧版plus-pkgs.nginx.com软件仓库的现有系统(运行NGINX Plus R23或更早版本)上升级到NGINX Plus R26,则必须更新软件包管理器,使其指向新的pkgs.nginx.com/plus软件仓库。请参阅F5知识库中的说明。

如果是首次安装NGINX Plus R26,请参阅《安装NGINX Plus》中的《NGINX Plus管理指南》。

旧存储库中不提供NGINX Plus R26,该存储库将不再接收更新。

NGINX Plus API的OpenAPI规范访问方式变更

NGINX Plus软件包不再包含NGINX Plus API的YAML格式OpenAPI规范和Swagger UI。现在可在NGINX Plus管理指南中访问这些内容。

平台支持变更

新增支持的操作系统和架构:

  • Alpine Linux 3.15(x86_64,arm64)
  • 采用CentOS 8.1+、RHEL 8.1+和Ubuntu 20.04的IBM Z Platform (s390x);请参阅IBM Z s390x架构支持

已移除旧版操作系统:

  • Alpine Linux 3.11(支持的最低版本为3.12)

已弃用并计划在NGINX Plus R27中移除的旧版操作系统和架构:

  • Power8架构(ppc64le)
  • CentOS 8.1+
  • Alpine Linux 3.12

新功能详解

通过缓存JSON Web密钥集加快JWT验证

验证JSON Web Token时,NGINX使用JSON Web Key Set(JWKS)验证令牌签名或解密令牌。JWKS既可以存储在配置文件中,也可以通过HTTP请求从外部服务获取。此外,在内存中缓存JWKS还有以下几项优势:

  • 显著降低CPU使用率
  • 降低请求延迟
  • 简化JWT验证,因为在缓存过程中,JWKS密钥会从JSON转换为针对加密操作优化的二进制格式

要在内存中缓存JWKS,请添加新的auth_jwt_key_cache指令,并指定每个密钥集的过期时间(本例中为3小时):

正在加载代码示例…

从外部服务器获取JWK时,还建议配置标准的内容缓存,并添加proxy_cache_use_stale指令。该指令会让NGINX Plus在后台刷新已过期的JWKS期间继续提供该JWKS。

正在加载代码示例…

除JWKS缓存外,内容缓存还具有两方面的优势:

  • 韧性:即使JWKS已过期,仍可从缓存中检索。当JWKS提供方暂时不可用时,这可以提高韧性,但代价是安全风险增加。
  • 对授权服务器的影响:缓存的JWKS过期后,对授权服务器的影响会因JWKS缓存是单独使用还是与内容缓存结合使用而有所不同:
    • 仅使用JWKS缓存时,所有传入的授权请求都会转发到授权服务器,直至缓存中重新填充已过期JWKS的新版本。如果授权服务器响应缓慢,针对JWKS的重复HTTP请求可能会突然增加。这些额外负载可能会使授权服务不堪重负,导致问题进一步恶化。
    • 启用内容缓存并允许提供已过期的JWKS后,只有一个JWKS请求会转发到身份验证服务器,后续请求将进入队列,直到内容缓存填充完毕,NGINX能够处理这些请求。这样可以降低身份验证服务的负载,从而减少资源消耗。

强化TLS握手安全性

针对TLS的攻击(例如ALPACA)日益增多。为持续主动防御漏洞利用,我们已强化NGINX对TLS连接的处理。

应用层协议协商(ALPN)是TLS握手的一项可选扩展,客户端和服务器可在TLS握手期间使用该扩展,为握手所建立的加密会话选择要使用的第7层协议。ALPN最常见的用例是协商将浏览器与Web服务器或应用服务器之间的会话从HTTP/1.x升级到HTTP/2。

如果客户端通过ALPN提议的协议与正在建立的会话所对应的NGINX配置上下文不匹配,NGINX Plus现在会拒绝TLS握手。例如,在http{}上下文中定义的虚拟服务器需要HTTP的ALPN协议ID,而在mail{}上下文中定义的虚拟服务器则需要SMTP、POP或IMAP的协议ID。

NGINX Plus R26 引入了$ssl_alpn_protocol[HTTP][Stream]变量,用于捕获协商后的协议。(在$ssl_preread_alpn_protocols变量于stream{}上下文中随NGINX Plus R15引入,仍用于捕获客户端在握手期间通告的所有协议列表。)

此代码片段定义了alpn日志格式,该格式使用$ssl_alpn_protocol,将协议写入访问日志条目的alpn=字段。

正在加载代码示例…

新的“ssl_alpn”指令在“stream{}”上下文中定义NGINX Plus接受的协议。省略该指令后,NGINX Plus将考虑客户端提供的所有协议。

正在加载代码示例…

NGINX JavaScript模块增强功能

NGINX Plus R26集成了0.7.2版NGINX JavaScript模块(njs),并包含两项增强功能:

注意:本节假定您了解用于异步操作和加密操作的JavaScript结构。对代码片段的完整分析不在本博客的讨论范围内。

[编辑注:本节所述用例只是NGINX JavaScript模块众多用例中的一部分。有关完整列表,请参阅《NGINX JavaScript模块用例》。]

增强对异步函数的支持

在PHP等许多常用脚本语言中,命令和函数会同步执行。也就是说,脚本调用函数后会暂停(停止执行),直到该函数返回结果。

JavaScript也可以异步运行:异步调用函数时,脚本会继续执行,而不会等待函数返回结果。

请看以下示例脚本:

正在加载代码示例…

它返回空响应,因为njs运行时不会等待定义的超时期限结束(如果等待,输出将为b,a):

$ curl http://127.0.0.1/
$ 

要获得预期结果,正确处理异步操作显然至关重要。JavaScript提供了多种处理方式,但在常见的NGINX用例中,通常只需封装异步函数,使执行流程同步即可。这时就需要使用Promise对象以及async和await关键字。

ECMAScript 6(JavasScript的ECMA‑262语言规范第6版)将Promise对象定义为异步函数的返回类型。该对象有以下3种状态之一:

  • 已兑现,操作已成功完成
  • rejected,操作失败
  • pending,初始状态(既未兑现,也未拒绝)

使用关键字async定义JavaScript函数,会将该函数的返回类型设置为Promise。编写处理Promise对象的njs函数时,async和await关键字非常重要。

请看以下示例:

正在加载代码示例…

The fs.readFile函数(第12行)返回一个Promise。该函数封装在自定义async函数中,以确保仅当文件名为fs.readFile()时才调用user.text。由于使用了await关键字,封装函数会等待Promise完成,然后返回数据。

将fs.readFile()封装在另一个函数中,可以更轻松地捕获错误;async函数中的任何异常都会将Promise的状态设置为rejected。另一种方法是将第 9 行替换为返回已拒绝Promise的语句:

正在加载代码示例…

也可以直接使用Promise对象。在以下示例中,Promise.resolve函数分别为p1和p2返回一个Promise。Promise.all函数会等待p1和p2对应的Promise均得到解析,然后再返回结果。

正在加载代码示例…

现在,curl命令的输出符合预期(请注意,由于超时值较短,b会先返回):

$ curl http://127.0.0.1/b,a
$ 

使用WebCrypto API实现新的加密功能

NGINX JavaScript现在可通过WebCrypto API使用增强的加密功能。njs的常见加密用例包括:

  • 为会话ID生成安全随机数
  • 加密和解密消息、数据及Cookie
  • 使用对称和非对称加密算法创建或验证数字签名

以下njs代码会生成一个随机数:

正在加载代码示例…

以下NGINX Plus配置会调用njs代码:

正在加载代码示例…

该函数会输出一个随机数,如下所示:

$ curl 127.0.0.123225320050,3668407277,1101267190,2061939102,2687933029,2361833213,32543985,4162087386

WebCrypto中的getRandomValues函数非常适合用于初步了解安全随机数和WebCrypto。该函数的实现相当简单,并且会直接返回结果,而不是返回Promise。

不过,其他一些计算量更大的WebCrypto加密函数采用异步方式运行。例如,有关сrypto.subtle.digest()的文档指出:

为给定数据生成摘要。参数包括要使用的摘要算法标识符和要生成摘要的数据。返回一个Promise,该 Promise 将以生成的摘要兑现。

因此,直接调用“сrypto.subtle.digest()”并不能保证下一步可以获取其结果,除非将其封装在“async”函数中。这里使用关键字“async”和“await”将其封装在函数中,以确保函数返回前,结果已赋给hash变量:

正在加载代码示例…

此NGINX Plus配置中的js_set指令会将$hosthash变量的值设置为setReturnValue函数返回的值(该函数封装在host_hash函数中):

正在加载代码示例…

以下示例对主机名“example.com”进行哈希处理。

$ curl -H "Host: example.com" 127.0.0.1#
e8e624a82179b53b78364ae14d14d63dfeccd843b026bc8d959ffe0c39fc4ded1f4dcf4c8ebe871e657a12db6f11c3af87c9a1d4f2b096ba3deb56596f06b6f4

NGINX Plus R26 的其他增强功能

支持IBM Z(s390x)架构

随着现代应用不断拓展到各种数字环境,NGINX等关键支撑组件也需要随之部署。因此,我们很高兴地宣布,NGINX Plus现已支持采用CentOS 8.1+、RHEL 8.1+和Ubuntu 20.04的IBM Z (s390x)架构。希望利用现有大型机资源托管现代应用的组织,现在可以部署NGINX和NGINX Plus,将其用作基于软件的Web服务器、负载均衡器、反向代理、内容缓存和API网关。

Stream模块支持TCP半关闭

新的proxy_half_close指令支持独立关闭TCP连接的各个方向,从而提高stream{}上下文中的效率。

PCRE2库支持

旧版NGINX Plus使用Perl兼容正则表达式(PCRE)库(版本1)来评估NGINX配置中使用的正则表达式。这个重要的开源项目最近已终止维护,并由PCRE2取代。NGINX Plus使用PCRE2构建,但同时支持使用PCRE和PCRE2构建的动态模块,具体取决于底层操作系统提供的版本。无需更改配置。

升级或试用 NGINX Plus

如果您正在运行NGINX Plus,我们强烈建议尽快升级到NGINX Plus R26。升级后还可获得多项其他修复和改进,并有助于NGINX在您需要提交支持工单时提供帮助。

如果您尚未体验过NGINX Plus,建议立即试用。它可用于安全防护、负载均衡和API网关,也可作为获得全面支持的Web服务器,并提供增强的监控和管理API。立即开始30天免费试用。


分享

相关博客文章

NGINX Plus R26 正式发布
NGINX | 2022/02/15

NGINX Plus R26 正式发布

NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
NGINX | 2022/02/10

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击

gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
NGINX | 2021/09/13

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划

了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。

NGINX Plus R19 正式发布
NGINX | 2019/09/03

NGINX Plus R19 正式发布

NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。

NGINX现已正式加入F5
NGINX | 2019/05/09

NGINX现已正式加入F5

NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。

使用NGINX和NGINX Plus实现高性能缓存
NGINX | 2016/08/24

使用NGINX和NGINX Plus实现高性能缓存

我将介绍NGINX在内容缓存和性能方面的工作原理,并分享一些控制NGINX内容缓存方式的技巧。