NestedTokenLoader: read "cty" from the JWE protected header only

未关闭 适合新手
#757 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
74/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
php

调研方向

先阅读 NestedTokenLoader::checkContentTypeHeader() 及其使用的 JWE 头部访问器;将它们与把 cty 写入受保护头部的 NestedTokenBuilder 进行比较。修改检查逻辑,使其仅接受来自共享受保护头部的 cty,然后检查或添加 JSON 序列化相关测试,覆盖 cty 仅存在于非受保护头部的情况。完成标准是该情况会被拒绝,同时受保护的 cty 仍可正常工作;issue 未指定测试文件。

由索引模型根据 Issue 内容生成。

描述

enhancement
Version(s) affected

All versions since nested tokens were added (1.1.0): 3.4.x, 4.0.x, 4.1.x, 4.2.x, and the 4.3.x and 5.0.x branches.

Description

NestedTokenLoader::checkContentTypeHeader() decides that a JWE carries a nested token from cty, read from the shared protected header, then from the shared unprotected header, then from the per-recipient header. The last two are not covered by the authentication tag of the JWE. A JWE issued without cty in its protected header can therefore be accepted as a nested token once it is serialized in a JSON form with cty in an unprotected member, which needs no key.

The impact is limited:

  • the JWE must decrypt with the application's keys, and the inner JWS must verify against the application's signature keys: nothing is forged or disclosed, and the inner signature is always checked;
  • a protected cty cannot be overridden or removed, because the headers must be disjoint;
  • the JWE loader must accept a JSON serialization;
  • with public-key key management (RSA-OAEP, ECDH-ES), anyone holding a valid JWS can already wrap it in a JWE with a protected cty.

What remains is a confusion between a JWE the issuer marked as a nested JWT and a JWE around a JWS that the issuer did not mark. NestedTokenBuilder always writes cty in the protected header, and JWTs use the compact serialization, where every header parameter is protected, so the unprotected locations are not needed. The rest of the library already reads security-relevant parameters from the protected header only (alg in JWSVerifier; JWEDecrypter does not take alg/enc from the shared unprotected header).

Possible Solution

Read cty from the shared protected header only. This refuses nested tokens from other producers that put cty only in an unprotected member of a JSON serialization. Either do it in 4.3.0 with an UPGRADE note, or accept that case with a deprecation in 4.3.0 and refuse it in 5.0.0.

Applications can enforce it today with a protected-only cty checker among the header checkers of the JWE loader used by the nested token loader, for example new IsEqualChecker('cty', 'JWT') (protected-only by default, case-sensitive), or a CallableChecker doing a case-insensitive comparison.

Additional Context

Same pattern as GHSA-jc38-x7x8-2xc8 (a decision taken on an unprotected header), without its consequence: decryption and signature verification still use the application's keys.

Found by the Anthropic OSS Scanner (ANT-2026-YGYNZW0J).

主要语言
PHP
星标
954
派生
119
平均合并
48 分钟
30 天内合并 PR
17

环境准备

这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

web-token/jwt-framework 的其他 Issue

查看 web-token/jwt-framework 的全部 Issue

相似的 Issue

更多 PHP Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。