本节摘要:密码协议不是一份规则文档,而是一场对话——特殊性在于观众席上坐着一名不在角色表里的敌手。本节给出贯穿全册的四要素拆解法(角色、消息序列、安全目标、信任假设),并用 Needham-Schroeder 三步协议做第一次现场拆解。读完你能把任何协议描述拆成可分析的部件,并理解为什么"信任假设"是最常被含糊带过、也最常出事的那一项。
日常语境里"协议"指规则:TCP 是规则,HTTP 也是规则。这个理解拿到密码协议这里会缺一块。TCP 的世界里消息可能丢、可能乱序,但没有一个消息会"撒谎"——比特翻转了会被校验和发现,重传机制处理丢失。而密码协议的世界里,每个字节都可能被一个有目的的对手伪造、重放、篡改。规则文档描述的是角色"该做什么",密码协议的定义必须额外回答"如果有人不按规则来,会输掉什么"。
所以本册采用的工作定义是:密码协议是角色之间按消息序列达成的对话,它的每一条设计都必须对着一名具体的敌手来辩护。注意两个关键词。其一是"对话"——协议是动态的、有先后依赖的,第 2 步的正确性常常依赖第 1 步的某个性质成立,这是协议分析比原语分析难的结构性原因。其二是"辩护"——安全不是协议的属性,而是"协议 + 敌手模型 + 信任假设"这个三元组的属性;换了敌手模型,同一个协议的安全结论可以完全翻转。这个观念第 2 章会展开,本节先让你对"没有敌手模型就谈安全"这句话产生警觉。
拿普通通信协议对照一下更清楚。设计 TCP 的人不需要假设"网络里有实体想让两条连接混淆",所以它的序列号只要防"旧包乱入"这类概率性事故。而设计 TLS 的人必须假设存在一个能截获、修改、注入、重放任意消息的实体,并且在最坏情况下(私钥之外的一切都被看到)仍然要守住安全目标。假设的敌意强度不同,决定了协议的每一行设计都长得不一样。
拿到任何一份协议描述(论文里的图、标准里的流程、代码里的函数调用序列),我建议用同一个框架把它拆成四样东西,缺了哪样就先追问哪样:
| 要素 | 追问 | 含糊带过的典型后果 |
|---|---|---|
| 角色 | 谁在说话?各自知道什么、想证明什么? | 角色数被悄悄增加(内部服务也算角色),攻击面算漏 |
| 消息序列 | 按什么顺序说?每条消息里有什么、谁加密谁签名? | 顺序依赖被忽视,重放与反射攻击藏在顺序里 |
| 安全目标 | 防住什么算赢?机密性还是认证性?对谁? | 目标写成"安全通信"这类不可判定的话,没法验证也没法测试 |
| 信任假设 | 什么默认可信?公钥怎么绑定身份?时钟谁提供? | 最危险的一项:假设被攻破时,协议其余部分再精巧也全部归零 |
四者里前三个在文档里通常都写得出,第四个最常缺。原因不难理解:信任假设散落在"预置配置""运维流程""硬件保证"这些协议文本之外的地方,写协议文档的人觉得那是别人的事。但推演室的纪律是:假设必须被显式列出,因为敌手的第一个攻击目标永远是假设本身。攻不破数学,就攻时钟;攻不破时钟,就攻发时钟信号的那个内部服务。
用经典的 Needham-Schroeder 公钥三步协议做第一次拆解(它是 3.1 节名案的主角,这里只做结构拆解不做攻击)。记号:A、B 是两个角色,Ka、Kb 是各自的公钥, Nab、Nba 是各自生成的随机数(称为临时值),花括号加下标表示"用谁的公钥加密"。
消息1 A -> B : {A, Na}Kb A 用 B 的公钥加密自己和临时值,发给 B 消息2 B -> A : {Na, Nb}Ka B 解出 Na,附上自己的 Nb,用 A 的公钥加密送回 消息3 A -> B : {Nb}Kb A 解出 Nb 作为回执,证明自己能解开 Ka 下的消息
按四要素过一遍。角色:A(发起方)与 B(响应方),双方都希望确认"我在和本人对话,且只有我们俩知道这两个临时值"。消息序列:三步,每一步都是对上一步密码学验证的回应。安全目标:协议结束时 A 确信 B 在线且持有对应私钥,B 确信与自己对话的是 A,双方共享两个只有彼此知道的临时值,可派生会话密钥。信任假设:这一步立刻卡住了——A 凭什么相信 Kb 就是 B 的公钥?协议文本里没有答案。答案在协议之外:公钥基础设施、预置的密钥表、或者当面交换。NS 论文当年没有显式回答这个问题,这正是它日后被找到漏洞的土壤(完整故事在 3.1 节)。
再做一个变式练习,体会"换假设换结论":假设 A 和 B 之间提前共享了一个长期对称密钥 Kab,把上面三步改写成对称版本(用 Kab 替换公钥运算),三步协议能否还成立?你会发现消息结构需要重新设计——对称密钥下"谁加密的"和"谁在说话"绑定方式不同。这个练习不用现在做完,留到 1.3 节学完积木后再回头,感受会深得多。
有人会问:四要素拆解听起来是学院派动作,工程评审里真的用得上吗?用得上,而且恰恰是评审里最值钱的动作。真实的协议评审文档大多长这样:一图消息流,加一句"本协议保证端到端安全"。四要素拆解法逼你把这半页材料撑开成四份清单——角色表会暴露"参与方其实有五个而不是两个"(客服系统、日志系统、推送服务都是角色);消息序列表会暴露"第 3 步引用了第 2 步的值,但第 2 步可能根本没发生"(离线场景下的顺序假设);安全目标表会把"保证安全"逼成三个可判定的谓词;信任假设表则几乎总能找出至少一条没人负责的假设。评审会上最有价值的一句话往往就是:"这条假设谁在守?"
第二个常见疑问:四要素和后面章节的威胁建模清单(2.2 节)是什么关系?可以说 2.2 节是四要素的"敌手视角重排"——角色表变成资产与入口,信任假设表变成攻击目标的优先级清单。先在本节把四要素练熟,到 2.2 节只是换一个排列方向,学习成本已经在本节付掉了。
第三个疑问来自数学基础不自信的读者:模运算和异或之外的东西没学过,能不能做协议分析?我的答案是先动手,数学可以边用边补。协议逻辑层的分析——本册花最多笔墨的那一层——几乎不依赖数学细节,它依赖的是"谁在什么时候知道什么"的记账能力,这份能力四要素拆解练十次就有。真正需要数学深水区的只有两处:评估原语本身的强度(那更多是密码学研究者的辖区,工程上采信参数建议即可),以及读懂 6.2 节的归约证明骨架(需要知道"多项式时间"和"可忽略概率"两个词的日常含义)。把数学焦虑放在一边,从记账开始,是进入这门手艺阻力最小的路径。
下一节我们把安全目标里的三个关键词拆开细讲:机密性、完整性、认证性,每个都按"被攻破时抓包里看到什么"来判断。带着本节的四要素表,你会在那一节发现属性从来不是抽象名词,而是挂接在具体消息上的谓词。