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

本文阐述MCP参数级授权的核心原则:租户身份不可由调用参数自报,必须通过可信令牌与后端对象归属校验双重确认。强调OAuth2.1草案在授权链中的定位、对象级授权的必要性、多租户隔离的强制检查点,以及缓存键需纳入权限模型(含主体、租户、授权版本)。所有授权约束须有服务端明确验证,杜绝跨租户越权访问。

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协议。

缓存键也属于权限模型

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

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

参考资料

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值