flawopen.com/Teardowns/cve-2022-31150-undici-crlf-injection
CVE-2022-31150:Undici の CRLF 注入
CVE-2022-31150 では未検証の CR/LF が Undici のリクエスト生成に到達しました。上流の修正と更新方法を解説します。
HTTP リクエストは、行の区切りが決まった用紙のようなものです。各行には一つの項目があります。未検証の文字列を転記すると、隠れた改行によって後続部分が新しい項目に見えることがあります。Undici の修正は、書き込む前にヘッダー値、メソッド、パスを検証します。
主要な概念と専門用語
Undici- Node.js 用 HTTP/1.1 クライアントライブラリ。Node.js の組み込み fetch にも Undici が含まれます。
CRLF 注入- 信頼できない復帰・改行バイトがプロトコルのフィールドに入り、行境界を変えられる状態です。
HTTP token- ヘッダー名やメソッドなど、プロトコル要素に許される制限付き文字集合です。
リクエストターゲット- HTTP リクエストで送信するパスとクエリです。制御文字で構造を変えてはいけません。
フレームワーク対応
- このガイドで説明する弱点の CWE 参照: CWE-93
根本原因の分析 (Root Cause)
修正前の Undici は、信頼できない入力に由来する不正な制御文字を含むヘッダー値をリクエストへシリアライズする可能性がありました。CR/LF は行区切りであり、受け入れるとヘッダー行を注入または破損できます。上流パッチはヘッダー名を HTTP token として検証し、値の不正文字を拒否し、メソッド token を検証し、パス内の制御文字を拒否します。GitHub アドバイザリは 5.8.0 未満を対象範囲とし、NVD の説明は 5.7.1 未満としています。どちらも修正版は 5.8.0 です。これはクライアントのリクエスト注入であり、SSRF や認証情報の露出が自動的に起きるわけではなく、アプリとネットワーク経路に依存します。
ステップ・バイ・ステップの攻撃フロー
1. 未信頼の値
アプリのデータが Undici のヘッダー、メソッド、またはパスに渡ります。
2. 検証不足
影響を受けるバージョンでは、不正な制御文字がリクエスト生成に入る可能性がありました。
3. プロトコル境界
HTTP のシリアライズは行境界を使います。制御文字を受け入れるとフィールドを注入・破損できます。
4. 修正と抑制
Undici 5.8.0 はシリアライズ前にヘッダーのバイト、メソッド token、パス文字を検証します。影響は状況によります。
ソースコード比較:脆弱 vs 堅牢化
// 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`;
}
エンジニアリング&システム堅牢化チェックリスト
- ✓npm の undici を 5.8.0 以降に更新します。組み込み fetch では、サポート対象 Node.js に含まれる Undici のバージョンを確認し、Node.js を更新します。
- ✓未信頼のヘッダー値にある不正な制御文字を拒否します。意味が曖昧な入力を、文字を黙って削除して処理し続けないでください。
- ✓HTTP の生テキストを組み立てず、Undici の構造化リクエスト API を使用します。
- ✓制御文字を含むヘッダー名・値、メソッド、パスの回帰テストを追加し、送信前に拒否されることを確認します。
- ✓利用者が宛先を指定できるアプリでは、別途、宛先許可リストとネットワーク送信制御を設けます。これは多層防御であり、CVE 自体の修正ではありません。
- ✓ロックファイルと推移的依存を確認し、脆弱な Undici が残っていないことを確かめます。