博客 | NGINX

宣布推出 NGINX Plus R26

NGINX-F5-horiz-black-type-RGB 的一部分
罗伯特·海恩斯缩略图
罗伯特·海恩斯
2022 年 2 月 15 日发布

我们很高兴地宣布NGINX Plus Release 26 (R26)已经推出。 NGINX Plus 基于 NGINX 开源,是唯一Web 服务器、负载均衡器、反向代理、内容缓存和 API 网关于一体的软件。

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

  • 使用 JSON Web 密钥集缓存实现更快的 JWT 验证——继续在过去几个版本中添加的一系列对 JSON Web Tokens(JWT)支持的增强功能,我们引入了 JSON Web 密钥集(JWKS)的内存缓存,这大大减少了 JWT 验证的开销。
  • 强化 TLS 握手- 如果客户端通过 ALPN 提出的通信协议与正在建立的会话的 NGINX 配置上下文不匹配(例如,在http{}上下文中向虚拟服务器提出 IMAP 电子邮件协议),NGINX Plus 将拒绝 TLS 握手。
  • NGINX JavaScript 模块的增强- 现在支持使用asyncawait关键字和Promise对象的异步函数,并且我们已经实现了用于加密操作(如生成随机数或加密 cookie)的 WebCrypto API。

此版本还支持IBM System Z (s390x)架构、能够独立关闭 TCP 连接的每个方向,以及支持 Perl 兼容正则表达式 (PCRE) 库的第 2 版。

行为方面的重要变化

NGINX JavaScript 模块不再支持js_include

正如NGINX Plus R23发布时宣布的那样,在版本0.4.0NGINX JavaScript 模块中的js_import指令取代了js_include指令。 js_include指令当时已被弃用,并且从此版本开始不再受支持。

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

  1. 编辑 NGINX 配置文件:

    • js_include替换为js_import ,并记下隐式module_name (指令的 JavaScript 文件名参数,不带.js扩展名)。

    • 在每个引用 JavaScript 函数的指令中,在函数名称前加上module_name前缀。 函数名称是这些指令的第一个参数:

      它是js_set [ HTTP ][ Stream ] 指令的第二个参数。

    例如,更改:

    js_set $foo 我的函数;
    

    到:

    js_set $foo模块名称.myFunction;
    
  2. 编辑定义 NGINX 配置文件中引用的函数的 JavaScript( module_name .js )文件。 向每个文件添加如下的导出语句,命名引用的函数。

    导出默认 { myFunction, otherFunction }
    

    export语句可以出现在.js文件中的任何位置,但按照惯例,它要么直接放在函数上方,要么放在文件的末尾。

Cookie-Flag 模块已过时

第三方 Cookie-Flag 模块在NGINX Plus R23中已被弃用,并且当时宣布,自此版本起,该模块不再在NGINX 模块存储库中可用。

在升级到NGINX Plus R26之前,请编辑您的 NGINX 配置,用内置的proxy_cookie_flags指令替换任何出现的set_cookie_flag指令(在弃用模块中定义)。

TLS 协商不再支持 NPN 协议

NGINX 建立 TLS 和 HTTP/2 连接的方式已更新。 作为 NGINX 和客户端(通常是浏览器)之间 TLS 握手的一部分,它们协商在握手建立的会话中将使用哪种通信协议(通常,协商将会话从 HTTP 1.x升级到 HTTP/2)。 TLS 的下一代协议协商 (NPN) 扩展是用于此目的的第一种方法,但 NPN 现已被认为已过时,并被发布为RFC 7301 的application层协议协商 (ALPN) 扩展所取代。

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

此外,我们的 ALPN 实现已经得到扩展和强化 - 请参阅强化 TLS 握手

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

NGINX Plus R24发布时,所有 NGINX 软件的软件包存储库都进行了重新组织,从而改变了 NGINX Plus 的安装过程。

当您安装或升级 NGINX Plus 时,操作系统的包管理器( aptyum或同等软件)会配置 NGINX Plus 的软件存储库。

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

如果要执行NGINX Plus R26的初始安装,请参阅NGINX Plus 管理指南中的安装 NGINX Plus

NGINX Plus R26在旧存储库中不可用,不会收到进一步的更新。

更改了对 NGINX Plus API 的 OpenAPI 规范的访问

NGINX Plus 软件包不再包含 YAML 格式的OpenAPI 规范NGINX Plus APISwagger UI 。您现在可以在NGINX Plus 管理指南中访问它们。

平台支持变更

支持的新操作系统和体系结构:

  • Alpine Linux 3.15(x86_64,arm64)
  • 带有 CentOS 8.1+、RHEL 8.1+ 和 Ubuntu 20.04 的 IBM Z 平台 (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 Tokens 时,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 的重复 HTTP 请求可能会突然增加。 这个额外的负载可能会使身份验证服务不堪重负,从而使问题更加严重。

    • 当启用内容缓存并提供过期的 JWKS 时,只有一个 JWKS 请求会转发到身份验证服务器,后续请求将排队,直到内容缓存填充后 NGINX 可以满足它们。 这会降低对身份验证服务的需求(从而降低资源消耗)。

强化的 TLS 握手

针对 TLS 的攻击(例如ALPACA )正在增加。 作为我们持续致力于主动防御漏洞的一部分,我们加强了 NGINX 对 TLS 连接的处理。

application层协议协商 (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 ] 变量来捕获协商的协议。 ( NGINX Plus R15中的stream{}上下文中引入的$ssl_preread_alpn_protocols变量仍然捕获客户端在握手期间通告的所有协议的列表。)

此代码片段定义了alpn日志格式,它使用$ssl_alpn_protocol将协议包含在访问日志条目的alpn=字段中。

 

stream{}上下文中的新ssl_alpn指令定义了 NGINX Plus 接受哪些协议。 省略该指令以使 NGINX Plus 考虑客户端提供的所有协议。

 

NGINX JavaScript 模块增强功能

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

笔记: 本节假设您了解异步和加密操作的 JavaScript 构造。 对代码片段的完整分析超出了本博客的范围。

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

增强对异步函数的支持

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

JavaScript 还可以异步操作:当异步调用一个函数时,脚本会继续执行,而无需等待函数返回结果。

参见此示例脚本:

 

它返回一个空响应,因为 njs 运行时不会等待定义的超时时间过去(如果它等待,则输出将是b,a ):

$ curl http://127.0.0.1/$ 

正确处理异步操作显然对于获得预期结果至关重要。 JavaScript 提供了多种方法来做到这一点,但在常见的 NGINX 用例中,通常希望简单地包装一个异步函数,以使执行流同步。 这就是Promise对象和asyncawait关键字发挥作用的地方。

ECMAScript 6 (JavasScript 的 ECMA-262 语言规范的第六版)将Promise对象定义为异步函数的返回类型。 它存在于以下三种状态之一:

  • 已完成– 操作已成功完成
  • 拒绝– 操作失败
  • 待处理– 初始状态(未完成或拒绝)

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

请看这个例子:

 

fs.readFile函数(第 12 行)返回一个Promise 。 它包装在一个自定义异步函数中,确保仅当文件名为user.text时才调用fs.readFile() 。 由于await关键字,包装函数等待Promise并返回数据。

fs.readFile()包装在另一个函数中可以更容易地捕获错误;异步函数中的任何异常都会将Promise的状态设置为denied 。 另一种方法是用返回被拒绝的Promise的语句替换第 9 行:

 

您还可以直接使用Promise对象。 在以下示例中, Promise.resolve函数为p1p2分别返回一个PromisePromise.all函数等待p1p2的承诺都得到解决后才返回结果。

 

现在我们的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

因此,直接调用сrypto.subtle.digest()并不能保证其结果可用于下一步,除非它被包装在异步函数中。 因此,我们在这里用asyncawait关键字将其包装在一个函数中,以确保在函数返回之前哈希变量被填充结果:

 

此 NGINX Plus 配置中的js_set指令使用setReturnValue函数返回的值(包装在host_hash函数中)填充$hosthash变量:

 

下面是对主机名example.com进行哈希处理的示例。

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

NGINX Plus R26 中的其他增强功能

支持 IBM Z (s390x) 架构

随着现代应用占领每个可用的数字生物群落,像 NGINX 这样的基本生命支持组件随之移动就变得非常重要,因此我们很高兴在IBM Z (s390x)架构上使用 CentOS 8.1+、RHEL 8.1+ 和 Ubuntu 20.04 支持 NGINX Plus。 希望在现有大型机资产上托管现代应用的组织现在可以将 NGINX 和 NGINX Plus 部署为基于软件的 Web 服务器、负载均衡器、反向代理、内容缓存和 API 网关。

流模块中的 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 网关,或者作为具有增强监控和管理 API 的完全支持的 Web 服务器。 您今天就可以开始享受30 天免费试用


“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”