fix(mcp): OAuth 回调服务器实际校验 state 参数 (#16)#82
Merged
Conversation
#16 报告 OAuthCallbackServer.state_param 永远是空字符串, parse_callback_url 中 `if !expected_state.is_empty() && state != expected_state` 条件永远跳过 state 校验。本地回调服务器(127.0.0.1:随机端口)接受任意 state 值并传给 rmcp::OAuthState::handle_callback,rmcp 校验若有缺陷则无纵深防御。 修复:把 rmcp OAuthState 在 start_authorization 时生成的 state 从授权 URL 中提取出来,传给回调服务器做前置校验。 修改内容: - callback_server.rs 新增 set_expected_state(state) setter - oauth_flow.rs 在 get_authorization_url 之后调用 extract_state_param_from_url 提取 state 值,传给 callback_server.set_expected_state - oauth_flow.rs 新增 extract_state_param_from_url helper(用 url::Url 解析 query_pairs,state 缺失/URL 无效时返回 None,不 panic) - callback_server_test.rs 新增 3 个测试:setter 行为 / 严格校验 / 空值跳过 - oauth_flow_test.rs 新增 3 个测试:state 提取(命中 / 缺失 / 无效 URL) 特性/影响: - 行为兼容:set_expected_state 未调用时退化为旧行为(跳过校验) - rmcp::OAuthState::handle_callback 的二次校验不受影响 - 现在 state 不一致的回调会在 parse_callback_url 阶段被拒绝,不进入 handle_callback,提供纵深防御 Co-Authored-By: Claude <noreply@anthropic.com>
Owner
Author
PR Review: fix(mcp): OAuth 回调服务器实际校验 state 参数🔴 CI 失败:与 #81 相同的 unused import
🟢 OAuth state 验证 — 正确两个 commit 中 OAuth 部分(
🟢 测试覆盖 — 完整callback_server 3 个测试 + oauth_flow 3 个测试,覆盖 set/get、严格校验、空 state 跳过、URL 缺失、URL 无效。 总结修掉 |
cc-claws review #82 反馈:Windows clippy -D unused-imports 失败。 根因:mod tests 无条件 `use super::*`,但 restrict_to_owner_unix 在 Windows 上是 #[cfg(not(unix))] 的空实现,整个 tests 模块在 Windows 下没有任何引用 super 内容的代码,glob import 被判为未使用。 与 #81 commit 3e92a54 同样的修法: - 删除 `use super::*;` - 把对 restrict_to_owner_unix 的调用改为 super:: 前缀 - PermissionsExt 已经在每个 #[cfg(unix)] 测试函数体内 use,无需挪动 修改内容: - peri-tui/src/app/history_persistence.rs mod tests 删 use super::*, 两处 restrict_to_owner_unix 改为 super::restrict_to_owner_unix 特性/影响: - 不改变运行时行为,仅修复 Windows clippy Co-Authored-By: Claude claude-sonnet-4.6 <noreply@anthropic.com>
Owner
Author
|
@cc-claws 已修,commit 此 PR 在 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
关联 Issue
Fixes #16
问题
#16 报告
OAuthCallbackServer.state_param永远是空字符串:bind()中硬编码state_param: String::new(),导致parse_callback_url的if !expected_state.is_empty() && state != expected_state条件永远跳过 state 校验。虽然 rmcp 的
OAuthState::handle_callback在oauth_flow.rs:181做二次校验,登录流程本身仍受 rmcp 保护,但本地回调服务器(127.0.0.1:随机端口)接受任意 state 值并传给 handle_callback,缺乏纵深防御。改动
把 rmcp OAuthState 在
start_authorization时生成的 state 从授权 URL 中提取出来,传给回调服务器:mcp/callback_server.rsset_expected_state(state)settermcp/oauth_flow.rsget_authorization_url后调用extract_state_param_from_url提取 state 值,传给callback_server.set_expected_statemcp/oauth_flow.rsextract_state_param_from_urlhelper(url::Url::query_pairs解析;state 缺失 / URL 无效时返回None)特性 / 影响
set_expected_state未调用时退化为旧行为(跳过校验),现有调用方/测试无破坏OAuthState::handle_callback仍按 rmcp 内部逻辑校验 state,本次只是前置拦截parse_callback_url阶段就被拒绝(返回CallbackError::ParseFailed),不进入handle_callback验证
cargo check -p peri-middlewares无 warningtest_set_expected_state_updates_validation— passedtest_parse_callback_url_strict_state_validation_when_nonempty— passedtest_parse_callback_url_skip_validation_when_expected_empty(向后兼容)— passedtest_extract_state_param_from_url_present/_missing/_invalid— all passedcargo test -p peri-middlewares --lib mcp::callback_server— 13/13 passedcargo test -p peri-middlewares --lib mcp::oauth_flow— 9/9 passedTest Plan
🤖 Generated with Claude Code