English version · 区块链学习导航 · 上一篇
区块链学习 · 延伸文章 BCX014

某个主体现在没有编辑记录的权限,却可能有一条符合规则的路径,可以取得这项权限。反过来,移除它的编辑角色,未必能达到预期效果:如果它仍有权把该角色重新授予自己,就能再次取得权限。因此,访问审查需要分别回答两个问题:当前成员状态允许什么操作?在给定行动主体和规则下,还能到达哪些成员状态?
本文用一个完整的小模型回答这两个问题。三个虚构主体管理目录注释系统。我们逐步记录成员资格的变化,找出取得写入权限的最短路径,比较两种不同的移除结果,并证明一个有明确范围的恢复结论。练习不涉及钱包、真实合约、秘密信息、部署或实际权限调整。
模型刻意采用封闭边界。所有否定结论都依赖本文给出的完整规则,不能直接用来诊断未知的已部署应用。某次技术状态转换符合程序规则,也不等于组织已经批准,更不能证明任何主体打算执行它。
选择适合你的阅读路线
本篇目录
- 1. 完整的成员资格设定
- 2. 三种转换规则及其边界
- 3. A取得写入成员资格的最短路径
- 4. B和C回答的是不同问题
- 5. 移除管理者不会抹去其写入成员资格
- 6. 移除写入者可能留下单步返回路径
- 7. 最后一个R成员资格消失后会怎样?
- 8. 复现完整状态空间检查
- 9. 为什么根角色丢失后的计数仍是十六?
- 10. 迁移结论前先检查实现边界
- 11. 练习与参考答案
- 12. 写出证据真正支持的结论
- 来源与版本说明
- 要区分当前权限与未来可取得的能力,阅读第1—4节。
- 要理解为什么某些移除没有消除可达权限,跟随第5—7节的独立案例。
- 要复核完整的有限状态检查及其边界,阅读第8—10节。
- 要检验理解,先完成第11节,再阅读参考答案和证据清单。
1. 完整的成员资格设定
系统只有三个主体A、B、C,以及三个角色:R代表根管理,M代表管理者,W允许写入一条无害的目录注释。这些名称只是符号标识。现实中的职位、资历或推测的所有者身份,不会额外增加权限。
初始状态中,A只持有R,B只持有M,C只持有W。其余六个“主体—角色”成员资格均为假。写入操作检查实际的W成员资格。因此,C能立即添加注释,A和B不能。模型没有规定R或M自动满足写入检查。
固定的管理关系为:admin(R)=R,admin(M)=R,admin(W)=M。每个表达式都应理解为改变成员资格时的授权条件。调用者需要R才能授予或撤销R,需要R才能授予或撤销M,需要M才能授予或撤销W。
这种关系不是操作权限的继承。尤其是,R到M再到W这条路径描述的是可能执行的管理变更,不会默默为R持有者补上缺失的M和W成员资格。状态必须真正改变,后续操作才能依据新成员资格通过检查。
在工作表中分别保留两项记录:固定的管理关系,以及会变化的成员资格表。把两者混成一张层级图,很容易回答错问题。前者决定哪些变更需要什么授权;后者决定此刻哪些变更和注释操作获得授权。
2. 三种转换规则及其边界
授予操作先检查调用者当前是否持有目标角色的管理角色。检查通过后,为目标主体添加该角色成员资格。撤销操作使用相同的当前状态检查,然后移除该成员资格。目标可以是A、B、C中的任何一个,也可以是调用者自己。
自行放弃有所不同。在调用者确认信息正确匹配时,主体可以移除自己的某项成员资格,不必持有该角色的管理角色。它不能借此移除别人的成员资格。本文每次成功的自行放弃,都假设满足了所需的确认匹配条件。
授权或确认检查失败的调用不改变状态。已获授权但重复授予已有角色,或者移除本来就不存在的成员资格,也不改变成员资格表。这些属于状态图中的自环。在可达性搜索中省略它们,不会漏掉通往不同状态的路径。
每次成功变更都是原子的。下一次调用检查的是上一次调用产生的状态。模型没有同时操作、延迟生效、外部模块、新主体、可变管理关系、升级、对外暴露的内部授予函数或隐藏恢复入口。在限定某个主体独自行动的路径中,也不能暗中让另一个主体帮忙。
这些教学规则参考了固定版本实现,但不表示我们编译或执行了Solidity。OpenZeppelin公开的授予、撤销和自行放弃接口提供了有限的源码对照;完整配置与初始成员表则是课堂给定事实。M管理W是明确设定的配置,不能把它当成库未经配置时的默认关系。AccessControl v5.4.0。
3. A取得写入成员资格的最短路径
重置到初始设定,只允许A行动。A不能直接把W授予自己,因为这次授予需要M,而A当前没有M。持有R不会绕过这项具体检查。
A可以先把M授予A。调用者A持有R,而R是M的管理角色。转换成功后,A同时持有R和M。此时还没有执行任何注释操作,A也仍然没有W。
随后,A可以把W授予A。第二次调用看到刚刚取得的M成员资格,通过检查并添加W。A现在持有R、M、W。之后的写入操作才会通过成员资格检查。
因此,最短的有效变更路径包含两次授予。零次变更不行,因为A初始没有W。一次变更也不行,因为唯一能添加A的W的转换,要求A在该转换之前已持有M,而初始状态不满足。在给定的独自行动规则下,必须先取得M。
这条两步路径证明的是可达的技术能力。它不证明A已经执行调用,不证明组织批准过,也不证明所有部署都存在同样的路径。访问报告应保留这些区别:初始没有写入权限;在模型中经过两次获授权转换可取得写入成员资格;未提供实际执行证据。
4. B和C回答的是不同问题
再次重置,只允许B行动。B已经持有M,因此可以通过一次变更把W授予自己。它随后同时持有M和W。最短路径长度为一,因为B初始缺少W,但已经满足授予所需的管理条件。
B不能在这个独自行动模型中取得R。添加任何R成员资格都需要持有R的调用者。B初始没有R,其允许执行的变更也不能凭空产生所需的第一个R成员资格。虽然A存在且持有R,但只允许B行动的搜索不能借用A的帮助。
对C而言,取得写入权限的最短路径长度是零,因为C已经持有W。这不会赋予C管理W、M或R的权力。写入成员资格属于操作权限,不等于挑选其他写入者的权限。
C可以自行放弃W。此后C没有任何角色,在没有其他主体参与时无法恢复自己的W。即使C不能通过管理角色检查去授予或撤销角色,这条放弃路径仍然重要。完整的转换模型必须包括失去权限的路径,而不只是取得权限的路径。
现在可以作出准确比较:A的可达成员控制范围最广,却不能立即写入;B通过一次授予就能成为写入者;C能立即写入,却不能任命另一名写入者。仅按界面显示的角色数量排序,会完全忽略这种结构。
5. 移除管理者不会抹去其写入成员资格
另起一个案例,从原始设定开始。先由B把W授予自己,使B持有M和W。然后A撤销B的M。这次操作获得授权,因为A仍持有R,而R管理M。
结果是A持有R,B持有W,C持有W。B失去了管理者资格,但仍能通过写入检查。转换只移除了“B持有M”这一项;模型没有规定该移除会连带撤销“B持有W”。
这不是界面过期、更新延迟或撤销失败,而是给定操作成功执行后的准确结果。如果报告写成“管理者已移除,所以原管理者不能添加注释”,就额外引入了模型没有的规则。
要到达B既没有M也没有W的状态,模型需要对每项相关成员资格执行获授权的移除。例如,在移除B的M之前,B可以正确地自行放弃W;或者由一个M持有者撤销B的W。组织是否接受某条路径,不在纸面练习范围内。
关键是检查实际指定操作的后状态。撤销管理成员资格会改变后续管理能力,却不会自动撤销此前已经授予的操作成员资格。
6. 移除写入者可能留下单步返回路径
使用一次新的重置,让B再次取得W。这一次,B正确地自行放弃W,但保留M。B暂时无法通过写入检查,不过按照模型的下一次调用规则,它可以立即把W重新授予自己。
如果由M持有者撤销B的W,而B仍保留M,成员资格结果也是一样。移除操作叫撤销还是自行放弃,不会改变之后的管理检查。B仍持有重新授予W所需的前提资格。
在移除与重新授予之间取得的快照,确实会显示B没有W。但它不能证明B被持续排除在W之外。要评估更强的结论,必须按照给定行动主体假设,追踪从该快照出发的所有允许路径。
比较本节和第5节:前一个案例中,B失去M后仍保有立即写入权限;本节中,B失去立即写入权限,却保留恢复它的路径。这是“B已经被移除”这句含糊描述的两种不同缺陷。可验证的要求必须明确操作权限、管理路径、相关行动主体和后状态。
不要把这种比较当成实际移除操作指南。真实应用可能包含额外角色、合约、别名、升级机制或自定义授权。小模型的价值,在于让结论变得可检验,而不是假装一个标签或一笔成功交易就能解决所有问题。
7. 最后一个R成员资格消失后会怎样?
回到原始设定,让A正确地自行放弃R。剩余状态是B持有M、C持有W,没有任何主体持有R。仅在这个案例中,允许A、B、C合作执行之后的每一步获准转换。
即使合作,它们也无法在模型内重新产生R。逐类检查转换:授予R需要持有R的调用者,但现在没有;撤销只会移除成员资格;自行放弃也只会移除调用者的成员资格。没有任何一种转换能从当前状态产生第一个R持有者。
这是一条不变量论证:如果某个状态没有R成员资格,每个允许的下一状态也没有R成员资格。反复应用该论证,就覆盖了给定转换形成的所有有限序列,而不只是若干次失败尝试。
较低层级的能力并未消失。B仍持有M,可以改变W成员资格。C仍持有W,可以添加注释。B还可以自行放弃M;此后没有M持有者,而模型无法产生新的M,因为授予M需要R。
因此,“在封闭模型中无法恢复根管理”有证据支持;“整个系统停止运行”没有。“所有已部署合约在根角色移除后都永久无法恢复”也没有依据,因为那需要了解对应部署的全部路径和实现选择。
8. 复现完整状态空间检查
成员资格表由九个布尔项描述:三个主体各对应三个角色。因此最多有2的9次方,即512张不同的表。每次搜索期间,管理关系和允许行动的主体集合保持固定。
广度优先搜索从初始表开始,把它标为已见,并检查每个允许行动主体可执行的有效变更。对尚未见过的结果表,将其加入队列,并保存前驱状态与产生它的操作。队列耗尽后,已见集合就是这个有限模型的完整可达状态集合。
搜索包括获授权的授予、获授权的撤销,以及确认正确的自行放弃。每一步都依据当前表检查前提,不能始终使用初始表。当每次有效变更的成本均视为一时,第一次发现的写入状态给出最短转换路径。这里的长度是改变成员资格的调用次数,不代表时间、交易费用或操作难度。
独立复算结果为:A独自行动可达512个状态,B独自行动可达16个,C独自行动可达2个。根角色丢失后、三个主体合作的案例,可达16个状态。这些结果来自Python有限状态枚举,不是Solidity执行,也不是通用的合约验证证书。
计数应当能解释,而不只是被相信。对B而言,三个W成员资格有八种组合。B可在保留M时建立任意一种W组合,然后选择保留或自行放弃M。因此共有八乘二个状态;A的R始终不变。对C而言,只有保留或放弃C的W两种可能。
A能到达每一张成员资格表,因为它可以先建立设置目标成员资格所需的管理权限,再把自身权限的移除安排在最后。具体来说,它可以在保留必要权力时准备好较低层级成员资格,移除不需要的其他R持有者,并在所有依赖根管理的变更完成后才移除自己的R。最后的自行放弃不需要管理角色。这也解释了为什么从强大的初始位置出发,能到达没有任何管理者的表。
9. 为什么根角色丢失后的计数仍是十六?
在根角色丢失的起始状态中,三个R成员资格始终为假。A和C的M成员资格也始终为假,因为授予M需要R。只有B的M可以通过B自行放弃而改变。
只要B保留M,就能建立八种W组合中的任意一种。每种组合也都能在B没有M时出现:先建立该W组合,再放弃M即可。合作主体各自放弃角色,不会产生超出这些可能性的额外成员表类型。
因此,十六张可达表与零条R恢复路径可以同时成立。单看状态数量,无法判断你关心的具体目标是否可达。目标条件必须单独检查:到达的表中是否有任何一张包含R持有者?
同样,可达集合较小也不自动表示更安全。C的两状态集合包括主动失去唯一权限;根角色丢失后的集合既包括继续工作,也包括进一步失去管理能力。计数概括的是某个明确模型,不能独自评价治理质量、人的可靠性或系统韧性。
10. 迁移结论前先检查实现边界
固定版本的基础AccessControl源码包含内部状态修改函数和可覆写的扩展点。派生应用可能增加本文公开转换表面之外的路径。成员资格截图或不完整事件列表,不能证明这些路径不存在。AccessControl v5.4.0。
另一项扩展AccessControlDefaultAdminRules,对默认管理员采用带延迟的两步转移,并限制对该角色直接执行公开授予或撤销。它的自行放弃也有额外条件。因此,不能把本文直接改变R的转换原样复制到该扩展的模型中。AccessControlDefaultAdminRules v5.4.0。
实际审查需要准确的程序和配置、完整的相关主体集合、所有改变角色的入口、操作真正使用的授权条件,以及有依据的状态参照。新增时间或恢复规则,通常还需要新增状态变量和转换。模型改变后,结论必须重新计算。
证据里没有展示某条路径,意味着问题尚未解决。在一个明确完整的有限模型中证明路径不存在,才支持有边界的否定结论。区分这两种情况,才能把可审计论证与过度自信的关系图分开。
11. 练习与参考答案
- 初始状态下,A能添加注释吗?能直接把W授予自己吗?给出最短的成功替代路径。
- B取得W后,A撤销B的M。B还能添加注释吗?为什么?
- B持有M和W,然后自行放弃W。仅由B行动时,没有W的状态能持续保证吗?
- C在初始状态自行放弃W。C独自行动能恢复它吗?
- 在初始状态移除A唯一的R。B仍能任命写入者,是否与根角色不可恢复矛盾?
- 如果增加额外恢复函数,可以不检查它就沿用原来的根角色丢失证明吗?
答案:1. 两项立即操作都不能通过相应检查。A先把M授予自己,再把W授予自己,形成两次变更的路径。2. 能。移除M不会移除独立持有的W。3. 不能。保留的M允许B通过一次授予重新取得W。4. 不能;C没有管理成员资格,自行放弃也不会产生它。5. 不矛盾。M管理W,而恢复R需要R。6. 不可以。转换集合已经改变,不变量与枚举都必须重新检查。
延伸问题:原模型允许同时有两个R持有者吗?允许。A可以在保留自身R时把R授予B。这个答案针对给定的基础风格规则,不针对前文另行提及的单持有者扩展。该对照能快速检验读者是否把两个不同程序悄悄合并了。
12. 写出证据真正支持的结论
一份好的工作表,应在结尾分别说明四件事:当前操作成员资格、可达路径证据或有边界的不可能性证明、行动主体假设,以及证据边界。对A,可写“初始没有W;固定模型中存在两次授予的独自取得W路径”。对根角色丢失案例,可写“任何给定的合作转换序列均不能恢复R;较低层级操作仍然可能继续”。
在结论旁保留初始表、管理关系、准确转换规则、重置位置和最终表。若使用枚举,还应保留状态编码、完整转换生成方法、目标检查与预期计数。这样,另一位读者才能复现结果,并发现诸如遗漏自行放弃这类操作的错误。
值得养成的习惯很简单:把会变化的权限当成状态机来审查。当前角色列表回答当前状态的问题;完整转换模型回答接下来哪些能力可以取得、保留或失去。
来源与版本说明
主要源码于2026年10月12日核对。本文使用固定的v5.4.0版本,不声称所有更新版本或派生部署都具有相同规则。
- OpenZeppelin AccessControl v5.4.0:公开角色检查、自行放弃确认、可配置管理关系与扩展边界。
- OpenZeppelin AccessControlDefaultAdminRules v5.4.0:独立的管理员转移模型,仅用于说明本文设定的适用边界。
所有主体、目录操作和成员资格路径均为虚构。完整枚举是教学模型,不是调整实际访问权限的建议,也不构成生产系统恢复保证。
