
用DefaultHasher把消息算成一个数字,再把这个数字叫“签名”,不会得到可验证主体身份的令牌。普通哈希表散列器没有替应用定义密钥、算法、验证方或信任来源;这不是缺一条注释能补齐的问题。
MCP 2026-07-28版授权安全要求要求服务确认token确实发给自己,并明确禁止token passthrough。这个规范版本是七月资料,不把它包装成十月新发布。

验签之后还有什么
实际JWT验证应由成熟库按受信issuer、允许算法和正确密钥完成,并处理过期、生效时间和密钥轮换。不要从token自己提供的任意URL取密钥;也不要只解码payload就信任其中的声明。
验签通过以后,audience要匹配本服务;资源和scope还要满足具体操作。MCP的resource绑定目标资源服务器,下面的team-a则是自定义应用资源标识,两者不是规范中的同一个字段。服务若再访问上游,应取得面向上游的独立授权,不能把入站token原样透传。
只测应用规则,别冒充密码实现
以下FixtureClaims全部是本地构造输入。程序没有解析JWT或验证签名,仅演示在上游身份验证已经完成后,应用还需要怎样拒绝错误受众、过期、错误资源或缺失scope。
struct FixtureClaims<'a>{
audience:&'a str, resource:&'a str, scopes:&'a [&'a str], expires:u64
}
fn policy(c:&FixtureClaims<'_>,now:u64)->bool{
c.audience=="https://tool.example.invalid" &&
c.resource=="team-a" && c.scopes.contains(&"notes:read") && now<c.expires
}
fn main(){
let base=FixtureClaims{audience:"https://tool.example.invalid",resource:"team-a",scopes:&["notes:read"],expires:100};
assert!(policy(&base,99));
assert!(!policy(&base,100));
let wrong=FixtureClaims{resource:"team-ab",..base};assert!(!policy(&wrong,99));
let wrong=FixtureClaims{audience:"https://other.example.invalid",..wrong};assert!(!policy(&wrong,99));
let wrong=FixtureClaims{audience:"https://tool.example.invalid",resource:"team-a",scopes:&["notes:write"],expires:100};assert!(!policy(&wrong,99));
println!("5 fixture policy cases checked; no JWT parsed or signature verified");
}
rustc 1.98.0通过五项断言。example.invalid不是真实服务,100也是逻辑时刻。这段函数不能直接处理网络请求,结构体的存在更不能证明它里面的声明已经可信。
不用 starts_with 做租户隔离
team-a和team-ab名字相近,但应按规范化后的精确资源ID或明确的层级权限匹配。路径遍历、大小写、编码和别名也要按应用规则统一处理;简单字符串前缀无法替代这份策略。
本轮没有创建凭证、签发令牌或连接身份服务。实际集成仍缺issuer配置、验证库固定版本、重放与撤销策略及错误日志脱敏检查。代码测试只覆盖列出的策略条件,不能据此宣称完成安全授权系统。
博客强调JWT验证不能仅依赖签名,还需严格校验audience是否匹配本服务,并确保resource和scope满足具体操作要求;禁止token透传,需为上游请求获取独立授权;指出自定义哈希签名无效,反对用starts_with实现租户隔离,强调应使用精确资源ID或层级权限策略;同时提醒实际部署需配置可信issuer、固定验证库版本及完善撤销与日志策略。
401

被折叠的 条评论
为什么被折叠?



