FlawOpen

flawopen.com/Teardowns/cve-2022-31150-undici-crlf-injection

● CVE-2022-31150 · CVSS 5.3 · 中危
安全研究 · FlawOpen

CVE-2022-31150:Undici CRLF 注入

CVE-2022-31150 使不可信 CR/LF 进入 Undici 请求序列化。本文说明上游修复、影响范围和安全升级方法。

💡 通俗易懂的原理解析 (ELI5)

HTTP 请求像一张有固定换行的表单:每一行对应一个字段。如果未经检查就复制文本,隐藏的换行可能让后续内容看起来像新字段。Undici 的修复会在写入前检查请求头值、方法和路径。

核心概念与专有名词

Undici
Node.js 的 HTTP/1.1 客户端库;Node.js 的内置 fetch 也包含 Undici 实现。
CRLF 注入
不可信的回车和换行字节进入协议字段,可能改变行边界。
HTTP token
协议元素使用的受限字符集,例如请求头名称和方法。
请求目标
HTTP 请求发送的路径和查询;控制字符不得改变其结构。

框架映射

  • 本指南所述弱点的 CWE 参考: CWE-93

根本原因剖析 (Root Cause)

修复前,Undici 可能将含有无效控制字符的不可信请求头值序列化到 HTTP 请求中。CR/LF 是行分隔符;接受它们可能注入或破坏请求头行。上游补丁将请求头名称按 HTTP token 校验,拒绝值中的无效字符,校验方法 token,并禁止路径中的控制字符。GitHub 公告列出的受影响包版本为低于 5.8.0;NVD 描述为低于 5.7.1。两者均将 5.8.0 标为修复版本。这是客户端请求注入;SSRF 或凭据泄露并非必然结果,取决于应用和网络路径。

攻击执行流程分解

步骤 1

1. 不可信值

应用数据进入 Undici 的请求头、方法或路径参数。

步骤 2

2. 缺少校验

受影响版本可能让无效控制字符进入请求构造过程。

步骤 3

3. 协议边界

HTTP 序列化依赖行边界;接受控制字符可能注入或破坏字段。

步骤 4

4. 修复与限制

Undici 5.8.0 在序列化前校验请求头字节、方法 token 和路径字符;实际影响取决于上下文。

源代码对比:漏洞与安全实现

存在漏洞的实现
// a29a151 之前 lib/core/request.js 中相关的序列化位置
function serializeRequest(request, method, path, headers) {
  request.method = method;
  request.path = path;
  for (const [key, value] of Object.entries(headers)) {
    // 序列化前未验证协议字符。
    request.headers += `${key}: ${value}\r\n`;
  }
}
加固后的安全修复
// 上游请求解析器采用的强化验证模式
const token = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
const invalidFieldValue = /[^\t\x20-\x7e\x80-\xff]/;
const invalidPath = /[^\u0021-\u00ff]/;

function validateRequestTarget(method, path) {
  if (!token.test(method)) throw new InvalidArgumentError('invalid request method');
  if (invalidPath.test(path)) throw new InvalidArgumentError('invalid request path');
}

function processHeader(request, key, value) {
  if (!token.test(key)) throw new InvalidArgumentError('invalid header key');
  if (invalidFieldValue.test(value)) throw new InvalidArgumentError(`invalid ${key} header`);
  request.headers += `${key}: ${value}\r\n`;
}

工程与系统安全加固清单

参考来源