学习笔记7

第13章 密码协议导论

13.1 角色

  • 关于协议的交互双方,一般的描述是Alice和Bob,或者说是在客户(customer)和商家(merchant)之间进行。"Alice""Bob"或者"客户""商家"都不是特指某个个体或者组织,它们只是用来表示协议中的某个角色。
  • 单个实体可以充当协议中的任意一方角色。

13.2 信任

信任

  • 信任来源
    • 伦理道德。伦理道德对社会有很大的影响。尽管能够一直遵守伦理道德,从不违反的人很少(如果有的话),大多数人还是会在大多数的时候让自己的行为符合社会伦理道德。
    • 名誉。坏名声带来的威胁是人们检点自己举止行为的动机。
    • 法律。文明社会中,总是存在法律作为基础去支持对于那些举止不当的人进行检举和起诉。这同样给了人们检点自己举止行为的动机。
    • 人身威胁。害怕自己的欺骗行为被发现导致自己人身安全受到伤害。
    • MAD。Mutual Assured Destruction,亦称共同毁灭原则。MAD指的是一种对于你自身和其他各方都会造成伤害的威胁。
  • 以上所说的这些信任的来源均是使得某一方不去进行欺骗行为的动机,而其他方知道这个动机存在,从而觉得可以在一定程度上相信与他交互的另外一方。但是当你和完全不讲道理的人打交道时,这些动机都没有效果,因为你不能相信这些没有道理的人行动时会考虑自己能获取的最佳利益,这破坏了之前所有机制的根基。
  • 在网络上建立信任是很难的。网站要保护他的声誉,设立故障模式。
  • 信任并不是一个非黑即白的问题。

风险

  • 信任和风险
    • 信任是商业交易的基础,但它通常会被表示为风险而不是信任。
    • 风险可以看作是信任的对立,风险通常会被评估、比较或者被以各种形式进行交易。
    • 在讨论密码协议时,讨论信任的次数通常比讨论风险更多,但是缺少信任本身就是一个风险,有时可以通过专门的风险管理技巧来解决,例如保险。

13.3 动机

  • 密码协议在两个方面与动机机制有关。
    • 密码协议依赖于动机机制。一些电子商务支付协议无法阻止商家去欺骗客户,但是可以让客户掌握商户欺骗的证据。这样的机制是有作用的,因为它提供了一个经过加密的法庭上有效的证据。这样商家就有动机去让人们无法找到其欺骗的证据了,因为这些证据不仅可以在法庭上使用,也可以用来损害这个商家的名誉。
    • 密码协议改变了动机机制。协议使得一些事情不再可能发生,从而从需要考虑的动机机制里面消失了。密码协议也可以创造一些新的可能的动机。
  • 保持开放的心态,并且试图去理解什么在驱使人们的行为。之后再对应地调整你的协议。

13.4 密码协议中的信任

  • 密码协议的作用是最小化所需的信任的量。(最小化彼此信任的人数,以及最小化人们需要信任其他人的程度。)
  • 一个设计密码协议的有力工具称为偏执狂模型。任何在这个默认模型的基础上所做的修改都必须被文档记录下来。从商业的角度来说,在文档中列出所需的信任也就等于列出了所带的风险。协议中每一点需要的信任都对应着一个需要解决的风险。

13.5 消息和步骤

  • 个典型的协议描述包括在协议参与者之间发送的消息数量以及每个参与者需要做的计算。
  • 几乎所有的协议描述都是在很高的层次进行的。大多数的细节都没有描述。这样可以允许你把注意力放在协议的核心功能上,但同时它也产生了很大的危险性。如果不对每个参与者应当进行的行为进行小心的规范说明,那么这会使得协议的安全实现变得非常难。
  • 解决方案:模块化
    -对于密码协议或者通信协议,把所需的功能分为数个协议层(layer),每一层都位于它之前那一层的顶部。所有的层都很重要。但是多数的协议层对于所有协议来说其实是一样的、只有最顶部的协议层是高度差异化的,那一层则是找到的协议文档通常所在的部分。

13.5.1 传输层

  • 传输层指的是让人们能够互相通信的底层通信系统。
  • 这个系统负责将一系列的字符串从一个参与发送到另外一个参与者。关心如何能够在参与者之间发送字符串。
  • 在很多情况下,传输层需要一些额外的编码工作。
  • 我们期望传输层能够传输任意的字符串。在消息中有可能出现任意一个字节值。字符串的长度是可变化的。发送方发出去的字符串显然应当和接收方收到的字符串完全相同,删除结尾所有的零或者其他任何对字符串的修改都是不允许的。
  • 一些传输层会包括类似于魔数(magic constant)的东西、从而能提前检测出错误或者能够检查TCP流的同步是否正确。
  • 传输层提供了消息保密性、认证以及重放保护(replay protetion)。这使得密码协议更加容易实现,因为需要担心的攻击类型会少很多。

13.5.2 协议标识符和消息标识符

  • 协议标识符包括
    • 版本信息。为未来的升级提供空间。
    • 指定了这个消息属于哪个密码协议。
  • 消息标识符
    • 指出该标识符对应着协议的哪个消息。
  • 在这个层级并没有提供任何针对主动伪造的防护机制,只是帮助检测意外错误。
  • 协议和消息标识符同样使得消息能够更加独立,从而使得大多数的维护和调试工作变得简单。
  • 霍顿原则
    • 当我们在一个协议中使用认证(或者数字签名)时,我们一般是针对数条消息和数据字段进行认证。通过引入消息标识符,我们可以避免一个消息认证时被解读到错误的上下文里。

13.5.3 消息编码和解析

  • 编码层:。一条消息中每一个数据元素都需要被转化成一个字节序列。
  • 消息解析:接收者必须要能够解析看起来像一个字节序列的消息,
    将这个序列解析成其组成字段。这个解析不能被上下文信息影响。一个在所有协议版本中都是固定长度的字段是容易解析的。
  • 密码协议中的许多消息最后都会被签名或者认证。认证函数认证了一个字节串,并且通常在传输层对消息进行认证是最简单的。如果一个消息的解释取决于一些上下文信息,那么这个签名或者认证就是含糊不清的。
  • 编码方法:
    • TLV(Tag-Length-Value)编码
    • 每个字段被编码成了标签(tag)、长度(length)和值(Value)三个数据元素,标签用来识别字段,长度表示这个字段的值经过编码之后的长度,值则是被编码的实际数据内容。
    • XML
    • 使用一个固定的文档类型定义(Document Type Definition,DTD)时,这个解析就不依赖于上下文。

13.5.4 协议执行状态

  • 协议执行状态:在许多协议实现中,单个计算机有可能同时参加到几个协议执行中。为了记录所有这些协议的动向,需要某个形式来记录协议执行的状态。这个状态包括完成协议所必需的所有信息。
  • 实现协议需要某种类型的事件驱动编程,因为协议执行需要等待外部消息到达才能执行。这个目的可以通过多种方法来实现,比如说每个协议执行用单独的一个线程或进程,或者使用某种事件调度系统来实现。
  • 在给了一个事件驱动编程的基础设施之后,实现一个协议是相对简单的。协议状态包含了一个状态机,用于说明下一个消息的预期类型。作为一个通用的规则,其他类型的信息是不可接受的。如果符合期待类型的消息到达了,会根据对应的规则对它进行解析和处理。

13.5.5 错误

  • 错误
    • 协议通常包含了多种检查,这些检查包括验证协议类型和消息类型,检查这个消息是否是协议执行状态期待的类型,解析消息是否正确,以及执行协议指定的认证。如果里面任意一个检查失败了,我们就碰到了错误。
  • 安全的处理过程
    • 不给这个错误发送任何回复,并且马上删除协议状态。这样攻击者能够得到的协议信息最少。然而不幸的是,这样处理会导致一个不友好的系统,因为这个系统没有任何错误提示。
    • 要让系统易于使用,你通常需要添加一些错误信息。如果你能够摆脱它,就不要给协议中的其他方发送错误消息。在系统的安全日志里添加一个错误消息,这样系统管理员就能够诊断问题所在了。如果你必须发送一个错误消息,就让这个消息里包含的信息量尽可能少。一个简单的"出现错误"消息通常就足够了。
  • 错误与时间攻击联系
  • 错误处理这个问题很难给出一个简单的规则集合。
  • 足够小心,尽可能少地泄露信息。

13.5.6 重放和重试

  • 重放攻击
    • 攻击者录下来一段消息,然后将这段消息重新发送出去。
    • 这种攻击必须要防御,它很难检测。
  • 重试攻击
    • 进行协议交互时没有得到响应
    • 解决办法:重试
    • 可能出现的情况:
      • 你收到的消息和之前你已经响应过的消息有一样的消息标识符,并且内容也相同。
      • 收到一个和你最后响应过的消息有相同消息标识符,但是消息的内容不一样。
      • 收到一条甚至比你之前回复过的消息更"老"的消息。
    • 没有办法能够判断一个协议的最后一条消息是否已经到达。

第14章 密钥协商

14.1 初始设置

  • 协议的两个参与方Alice 和Bob,首先通过密钥协商协议设置一个秘密的会话密钥 k,然后将k用于一个安全的信道来传输实际的数据。

  • 在一个安全的密钥协商中,Alice 和Bob必须能够识别对方。现在我们只假设Alice和Bob 能够认证发送给对方的消息。基本的认证可以通过以下方式完成:

    • RSA签名(如果 Alice 和Bob知道对方的密钥或者正在使用公钥基础设施)
    • 通过一个共享密钥和一个 MAC 函数。
  • 为什么有了共享密钥还要做密钥协商呢?

    • 密钥协商可以将会话密钥和已经存在的(长期的)共享密钥分离开来。
      • 系统会变得更加健壮。
    • 共享密钥相对来说安全性比较弱。
      • 一些密码协商协议可以让一个很弱的密码变成一个很强的密钥。

14.2 初次尝试

在DH的基础上添加一些认证。

  • Alie 和Bob通过最初的两个消息来执行 DH协议。

  • Alice随后对会话密钥k计算认证并发送给 Bob,Bob检查了认证信息。

  • 同样的,Bob 也发送了关于k的认证信息并发送给 Alice。

  • 由于双方能够互相认证对方的信息,所以是能够检查\(Auth_A(k)\),并且 Alice 能够检查\(Auth_B(k)\)

  • 此协议存在的问题如下:

    • 对于DH协议,将参数 \((p,q,g)\) 设置为常数并不好。
    • 此协议使用了四条消息,然而如果要达到目的可以只需要三条消息。
    • 这个会话密钥被当作认证函数的输入,安全性无法保证。
    • 这两个认证消息太相似了,所以可信度不高。
    • 实现时要注意在认证消息交换之前不能使用k。

14.3 协议会一直存在下去

  • 修改一个协议并且需要能够和之前版本保持兼容是相对复杂的。
    • 需要实现这个协议的若干版本和一个决定使用哪个版本的系统。
  • 协议版本转换是一个可能被攻击的点。
    • 版本回滚攻击。
  • 设计协议时考虑未来可能的考验更加重要。
    • 不能给密钥协商协议指定一个固定的 DH 参数集合。
    • 即使我们选择了很大的一个集合,未来可能会出现密码学方面的改进强迫我们去改变它。

14.4 一个认证的惯例

  • 每次某一方发送一个认证,这个认证数据里包括了所有之前已经交换过的数据∶所有之前的消息和所有已经认证的消息中包括的数据字段。
  • 认证器同样会考虑(计算)所有通信各方的身份识别符。
  • 这个惯例所需代价很小,却去除了很多可能攻击的空间。
    • 不必交换大量数据
    • 认证计算从计算输入字节串的散列值开始
    • 散列函数的速度很快
  • 这个惯例同样让我们可以缩短符号表示。
    • \(Auth_A(X,Y)\) ——> \(Auth_A\)
  • 认证函数只会认证一个字节串。
    • 每个要认证的字节串必须从一个独特的识别符开始。这个识别符能够识别协议中这个认证器被使用的具体位置。
    • 将之前消息和数据字段编码进这个字节串所使用的编码方法必须能够让这个字节串在没有其他上下文信息的情况下把消息和数据字段恢复出来。

14.5 第二次尝试

  • 我们不再有固定的 DH参数了,我们只使用两条消息,不在任何地方直接使用认证密钥,并且认证惯例确保了被认证的字节串不是相同的。
  • 新的问题如下:
    • 如果Bob有更加严格的安全策略,并且认为Alice选择的素数不够安全,那么他就会终止协议,使Alice选用新的参数重新开始协议。复杂化。
    • Bob缺少了“活跃度”,无法确定和他对话的是Alice还是重放者。
      • 解决方法:是让 Bob随机选择一个元素并让Alice的认证器进行计算。

14.6 第三次尝试

  • Alice她简单地发送她的最低要求给Bob,然后让Bob来选择这些参数。这样协议就变成了三条消息。
  • 问题:最终结果k是一个可变长度的数。系统的其他部分可能会觉得这个难以处理。
    • 在密码系统里面保留一个代数结构通常很危险。危险性在于攻击者可能会找到某些办法来利用这个结构。
    • 解决方法:将最终的密钥k进行散列。
      • 最终的密钥长度是固定的
      • 销毁了剩下的代数结构。

14.7 最终的协议

  • Bob需要为 \(p\) 选择一个合适的长度。
    • 这取决于Alice所要求的最小长度和他自己要求的最小长度。
    • Bob需要确保s的值是合理的。
  • Alice和Bob双方应当限制p的长度。但是,使用一个固定的最大值会限制灵活性。
    • 所以我们选择使用一个动态的最大值。
  • 会使用合适的DH参数的缓存。
    • 这给Bob节约了每次都要生成新的 DH参数的时间
    • 也给Alice节约了每次检查的时间
  • 注意:优化过多有可能会损坏原本的协议。

14.8 关于协议的一些不同观点

14.8.1 Alice的观点

  • Alice收到了来自Bob的一条消息,她确认这条消息来自于Bob因为它是认证过的,并且这个认证包括了她设置的随机数\(N\)
    • 这样的话其他人就没有办法伪造这条消息或者去重放一条旧消息。
  • Alice检查了这些DH参数是合理的,表明这个DH协议满足所有期望具有的性质。
  • 所以当Alice保留\(y\),发送\(Y\)时,她清楚知道只有使得 \(g^x=X\) 成立的 \(x\) 的人能够计算出最后的结果——密钥\(K\)
  • Bob认证了\(X\),并且Alice相信Bob只会在他执行协议的时候去认证X。所以,Bob知道这个合适的\(x\),并且一直保密。那么,Alice就可以肯定只有Bob能够得到这个最终的密钥\(K\)

14.8.2 Bob的观点

  • 他收到的第一条消息对他来说几乎没有什么有价值的信息。
  • Bob收到的第三条消息来自于Alice,因为Alice认证了这条消息.
    • 这个认证器包括了Bob选择的一个随机值\(X\),所以这个第三条消息不是重放消息.
  • Bob知道这些DH参数是安全的,因为是他选择的这些参数。
    • 所以他清楚只有知道满足 \(g^y=Y\) 的y值的人能够计算出最终的密钥\(K\)。这使Bob确信Alice是唯一能够计算出\(K\)的人。

14.8.3 攻击者的观点

  • 所以只要 DH协议的参数是安全的,被动攻击不会得到关于k的任何信息。
  • 尝试1:查看每个数据元素并且尝试改变它。
    • 但因为有认证所以在这里行不通。
  • 尝试2:把\(s_a\)改成更大的值。有3个问题:
    • 增加\(s_a\)并不能算是攻击,这只会使得 DH所用的素数更大,从而使得协议参数更强。
    • 两个认证的检查都会失败。
  • 多数设计者可能认为我们协议中的\(s_a\)可以不用认证,改变它也不会造成安全威胁。

14.8.4 密钥泄露

  • 若Alice或Bob仅仅丢失了自己的认证密钥,但是密钥还没有被攻击者知道,那么她/他只是失去了继续运行协议的能力。她/他仍然可以使用已经确定了的会话密钥。
  • 如果Alice失去了会话密钥但是还没有被攻击者得到,她就需要和 Bob再运行一次密钥 协商协议,再确定一个新的会话密钥。
  • 如果Alice的认证密钥被攻击者知道了,他就可以从那个时间开始,到Bob被通知并停止接受Alice的认证为止,一直模仿Alice的身份。
  • 密钥的主要功能∶控制特定功能的访问权限。
  • 前向安全性:Alice和Bob过去的通信能够仍然保密。即使攻击者知道Alice的认证密钥,即使攻击者将所有消息都录下来,他也无法找到已经完成的协议里的会话密钥k。

14.9 协议的计算复杂性

  • 假设DH参数的选择和验证都是事先缓存过的,那么就剩下了以下几个Alice和Bob都 必须进行的计算∶
    • DH协议子集里的三个指数运算。
    • 生成一个认证器。
    • 对一个认证器的验证。
    • 若干个相对有效的操作,例如随机数生成、比较、散列函数等。
  • 如果使用了对称密钥认证,协议的运行时间主要由 DH 协议参数的指数所决定。
  • 对于我们使用的公钥长度来说,DH协议的计算成本几乎和一个RSA 签名的计算成本相同。
    • DH运算仍然是协议计算里的主体部分,但是这个计算成本是合理的。

14.10 协议复杂性

  • 现实世界的系统里通常有很大的协议规范。
  • 通信可以非常复杂,加上密码函数和不信任,使得事情甚至更加难了。
  • 我们的建议是∶非常小心地处理协议的复杂性。

14.11 一个小警告

  • 用批判性、怀疑性的眼光去看待所有协议,甚至用专业的偏执眼光来看待是很重要的。

14.12 基于口令的密钥协商

  • 口令存在的问题使人们不会从一个很大的集合中选择。
    • 有一些程序会搜索所有可能的密码。
    • 理想状态下我们想要一个窃听者也无法进行线下字典攻击的密钥协商协议。
posted @ 2023-04-03 10:37  acacacac  阅读(38)  评论(0编辑  收藏  举报