欢迎光临
我们一直在努力

MCP参数级授权:租户身份不能由调用参数自报

MCP参数级授权:租户身份不能由调用参数自报

请求里带着tenant_id,并不意味着它来自这个租户。合法令牌也不意味着可以查询该租户的任意订单。身份、资源与对象权限需要连接起来。

从可信主体向内约束参数

MCP授权规范要求令牌用于正确的资源;OAuth2.1在该版本中引用的仍是IETF草案,不能把它写成已发布RFC。业务网关得到验证后的主体后,再把主体所属租户与对象所属租户比较。

模型可以提出查询对象,但不应替换可信上下文里的租户。只检查请求参数与令牌里某个字符串相同,也不足以证明数据库对象确实归属该租户。对象归属应由后端读取。

富授权请求可以表达更细权限,表达能力却不会自动变成执行效果。每个约束都应有明确的服务端检查点,包括字段集合、查询上限和对象级授权。

MCP参数级授权:租户身份不能由调用参数自报的边界与处理流程

图中身份、租户和对象三道门都需要通过;红色跨租户路径没有“改一下参数再试”的出口。

把对象归属加入授权条件

以下是可离线运行的最小示例,使用Python标准库。输入均为教学构造,不连接业务系统。

def authorize(principal, obj, args):
if principal.get("aud") != "orders-service":
return "DENY_AUDIENCE"
if principal.get("tenant") != obj.get("tenant"):
return "DENY_TENANT"
if set(args) != {"limit"}:
return "DENY_FIELDS"
n = args["limit"]
if type(n) is not int or not 1 <= n <= 20:
return "DENY_LIMIT"
return "ALLOW"

p = {"aud": "orders-service", "tenant": "a"}
o = {"tenant": "a"}
assert authorize(p, o, {"limit": 5}) == "ALLOW"
assert authorize(p, {"tenant": "b"}, {"limit": 5}) == "DENY_TENANT"
assert authorize(p, o, {"limit": True}) == "DENY_LIMIT"
assert authorize(p, o, {"limit": 5, "tenant": "b"}) == "DENY_FIELDS"
print("4 object authorization cases passed")

principal在此是假定已完成签名、发行者、受众和期限验证的可信对象。脚本没有解码JWT,没有实现OIDC或RAR协议。

缓存键也属于权限模型

缓存不能只按工具名和参数命中,还要考虑主体、租户、授权版本及对象变化。权限撤销后旧缓存是否仍能返回数据,需要专门的反例。

本例只验证参数和对象关系;没有真实令牌、授权服务器、数据库或撤销传播测试。

参考资料

  • MCP authorization
  • MCP security practices
赞(0)
未经允许不得转载:171主机测评 » MCP参数级授权:租户身份不能由调用参数自报
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址