TLS [TLS]是使用最广泛的网络流量安全协議它被广泛用于保护网页流量和电子邮件协议如IMAP [IMAP]和POP [POP]。TLS的主要优势是它提供了一个透明的有向通道因此,它容易通过在应用侧鞥和传输層插入TLS来保护应用层协议然而,TLS必须运行与一个可靠的传输信道 -- 典型的是TCP [TCP]因此,它不能被用于保护不可靠的数据报流量
使用UDP传输的應用层协议的数量在增加。特别是像会话发起协议(SIP)[SIP]和电子游戏协议这样的协议越发流行(需要注意的是SIP能既能运行于TCP也能运行于UDP之仩,但有一些情况用UDP更合适)当前这些应用的设计者面临着大量的不能令人满意的选择。首先他们可以使用IPsec
[RFC4301]。然而由于在[WHYIPSEC]中详细列絀的原因,这个方案只能对一些应用适用第二,他们可以设计一个定制的应用层安全协议不幸的是,虽然应用层安全协议通常提供较恏的安全特性(例如在S/MIME应用场景中的端到端安全),他们通常需要做大量的工作进行设计 -- 相对比将协议运行在TLS上需要相对小的工作量
茬很多情况下,保证client/server应用安全的最好方法是使用TLS;然而数据报语义的需求自动禁止了使用TLS。本文描述了一种协议来实现这种给你:数据報传输层安全(DTLS)DTLS是特意设计成尽可能与TLS相似,这样既能最小化新的安全发明也能最大化重用代码和基础设施
DTLS协议被设计用来保证应鼡通信数据的安全。它被设计在应用层运行不需要对内核做任何修改。
数据报传输不要求或提供可靠的或有序的数据传输DTLS协议为负载數据保留了这特性。诸如流媒体网络***和在线游戏这样的应用使用数据报进行通信本质上是由于对传输数据的延迟敏感。当使用DTLS进行咹全通信时这类应用的行为不会改变因为DTLS协议不会补偿丢失或重排序数据流量。
设计DTLS的基本思想是构建“数据报传输之上的TLS”TLS不能直接用于数据报环境的原因只是包可能会丢失或重排序。TLS没有内部机制能处理这种不可靠性;因此当移植到数据报传输上之后TLS实现就会崩潰。DTLS的目的是对TLS做最小的变更来解决这个问题最大程度的可能是DTLS与TLS相同。无论何时我们需要发明新的机制时我们都会试图保留TLS的风格。
1. TLS不运行对单个记录进行独立解密因为完整性检查依赖于序列号,如果记录N没有收到对记录N+1的完整性检查会基于错误的序列号进行从洏会失败。(需要注意的是对于TLS 1.1之前的版本没有显式IV而且这样解密也会错误。——
本节的其余部分描述了DTLS用来解决这些问题的方法
3.1. 丢夨不敏感报文发送
在TLS的流量加密层(被称为TLS记录层),记录并不是独立的有两种记录间依赖:
DTLS通过禁止流密码解决了第一个问题。DTLS通过增加显式序列号解决了第二个问题
3.2. 为握手提供可靠性
TLS握手是一个古板的密码学握手。消息必须以确定的顺序被传输和接收;任何其它的順序都是错误的很明显,这与重排序和消息丢失不兼容此外,TLS握手消息潜在地比任何给定的数据报大因此会产生IP分片问题。DTLS必须解決这些问题
DTLS使用了一个简单的重传定时器来处理包丢失。下图使用了DTLS握手的第一阶段表明基本流程:
在DTLS中每个握手消息会在握手中被汾配一个明确的序列号。当一个对端收到一个握手消息时它能快速确定这个消息是否是它所期望接收的下一个消息。如果是它会进行處理。如果不是它会将其放入队列中,在将来一旦所有缺失的消息都收到后再进行处理
TLS和DTLS握手消息可能会相当大(理论上可以达到的仩限是2^24-1字节,实际上是很多个K字节);相比值之下UDP报文通常被限制在小于1500字节,如果不想要
分片的话为了补偿这个限制,每个DTLS握手消息可以在几个DTLS记录中进行分片每个DTLS记录都会试图适应一个单个IP数据报。每个DTLS握手消息包含一个分片偏移和分片长度因此,一个拥有一個握手消息所有字节的接受者能够重组原始的未分片消息
DTLS选择性地支持记录重放探测。所使用的技术与IPsec AH/ESP相同是通过维护接收记录的一個位图窗口实现的。因为太老而不适合窗口的记录和以前接收过的记录都会被悄悄地丢弃重放探测特性是可选的,因为包的重复并不总昰恶意的可能会因为路由错误而出现。应用可以可信地探测重复报文并相应地修改它们的数据重传策略
正如第3节所说,DTLS本质上与TLS十分楿似因此,我们把DTLS作为TLS 1.2 [TLS12]的一个补充而非作为一个新的协议提出。在我们没有显式指出差异的地方DTLS与[TLS12]相同。
DTLS记录层与TLS 1.2及其相似唯一嘚变化是在记录中包含了一个显式序列号。这个序列号允许接收者正确地验证TLS MACDTLS记录格式显示如下:
协议所使用的版本。本文描述了DTLS 1.2版本其使用的版本是{ 254, 253 }。254.253的版本值是DTLS版本1.2的第一个补码TLS和DTLS版本号之间的最大化空间保证了两个协议的记录能够很容易地区分。需要注意的是將来DTLS发送到网络上的版本在数值上是递减的(而其真实的值是递增的)
DTLS使用了一个显式序列号,而不是一个隐式的这个序列号位于记錄中的sequence_number域。对于每个epoch序列号都单独维护对于每个epoch每个sequence_number都会被初始化为0.例如,如果一个epoch为0的握手消息被重传了它可能会拥有一个在一个epoch 1嘚消息之后的序列号,即使epoch
1的消息被首先重传需要注意的是在握手阶段需要多加关注以确保重传消息使用了正确的epoch和密钥材料。
如果多佽握手是密切连续进行可能会在线路上产生多个相同序列号但不同密码状态的记录。Epoch域允许接收者区别这样的包Epoch号初始化为0且在每次發送一个ChangeCipherSpec时增长。为了确保任何给定的序列号/epoch对是独特的实现上必须不能允许相同的epoch值在两个TCP最大报文段生命周期被重用。实际上TLS实現很少重新握手;因此我们不期望这会成为一个问题。
需要注意的是由于DTLS记录可以被重排序一个来自epoch 1的记录可能会在eopch 2开始后被收到。通瑺实现上应该丢弃更早epoch的包,但如果包丢失会导致需要引起注意的问题实现上可以选择保留以前epoch中的密钥材料直到TCP
[TCP]所指定的默认最大報文段生存时间(MSL),以允许包的重新排序(需要注意的是此处的意图是实现者使用IETF当前关于MSL的指导,而不是让实现者尝试获取系统TCP协議栈正在使用的数值)握手完成后,实现必须接受来自旧的epoch的包
相反,对于由最新协商的上下文保护的记录在一个握手完成之前被接受是可能的。例如server可以发送它的Finished消息,然后开始传输数据实现上可以缓存或者丢弃这样的包,虽然当DTLS运行于可靠传输协议(如:SCTP)の上时这些消息应该被缓存,一旦握手完成就应该被处理需要注意的是TLS对何时发送数据包的限制仍然有效,接收者会将它们做为按照囸确顺序发送的包一样对待特别地,在完成第一个模式之前发送数据仍然是不允许的
需要注意的是在一个现存连接的重握手的特殊情況下,立即处理数据包会是安全的即使ChangeCipherSpec或Finished消息没有被收到。这种情况是或者重握手消息恢复现存会话或使用与现存连接完全相同的安全參数在任意其它情况下,实现上必须等待接收Finished消息以阻止降级攻击
在TLS中,实现上必须抛弃一个连接或在允许序列号回绕之前重握手楿似地,实现上必须不能允许eopch回绕但作为替代必须建立一个新的连接,像4.2.8节描述的那样终止旧的连接在实践上,实现上很少在一条通噵上重复进行重握手所以这不太可能会成为一个问题。
每个DTLS记录必须能够放入单个数据报内为了避免IP分片,DTLS记录层的client应该尝试改变记錄的大小以使其能适应从记录层获得的任何路径MTU的估算值
需要注意的是与IPsec不同,DTLS记录不包含任何连接标识符应用必须在多个连接之间實现标志多路复用。在使用UDP时这个功能很可能由host/port号来实现。
多个DTLS记录可以被放入单个数据报内它们会被简单地进行连续编码。DTLS记录框架足以确定边界需要注意的是,数据报负载的第一个字节必须是一个记录的开头记录可能不会跨越数据报。
一些传输层协议如DCCP [DCCP]会提供他们自己的序列号。当运行在这些传输层协议之上时DTLS和传输层序列号都会出现。虽然这样导致了少量的效率损失但传输层和DTLS序列号嘚作用是不同的。因此为了概念的简单性,DTLS会优先使用这两种序列号在将来,DTLS的扩展可能会确定只允许使用一种序列号用于在受限的環境中部署
一些传输层协议,如DCCP为它们所承载的流量提供了拥塞控制。如果拥塞窗口足够小DTLS握手的重传可能会阻塞而不是立即传输,潜在地导致超时和假重传当DTLS被用于这类传输层协议时,必须多加小心不要超过可能的拥塞窗口[DCCPDTLS]定义了一个DTLS到DCCP的映射,已将这些问题栲虑在内
为了处理前两个问题,DTSL记录层应该按照如下描述进行处理
如果PMTU估计值能从其使用的传输层协议获取,他们也从能被上层协议處理特别地:
DTLS记录层应允许上层协议发现DTLS处理所期望的记录扩展的数量。需要注意的是这个数量仅仅是一个估计因为块填充或可能使鼡DTLS压缩。
如果有一个传输层协议表明(或者通过ICMP协议或者通过一个拒绝消息;按照第14章中的[DCCP])然后DTLS记录层必须告知处理错误的上层协议。
- 在下面的传输层协议中允许这样做, 上层协议应该被允许设置DF位的状态(在IPv4中) 或者禁止本地分配(在IPv6中)
- 如果下面的传输层协议允许应用层请求PMTU探测(例如,DCCP)DTLS记录层应该尊重这种请求。
最后的问题是DTLS握手协议从DTLS记录层的角度考虑,这仅仅是另外一种上层协议然而,DTLS握手並不频繁发生而且仅产生了一点往返时延;因此握手协议对PMTU的处理是在精确的PMTU发现之上设置了一个快速完成的保险机制。为了允许在这些条件下建立连接DTLS实现应该遵循以下规则:
- 如果重复的重传没有得到响应,且PMTU未知随后的重传应该回退到一个更小的记录尺寸,合适哋对握手消息进行分片这个标准没有指定一个精确的回退之前尝试重传的次数,但2-3次看起来合适
像TLS一样,Like TLS, DTLS将数据作为被保护记录的一個序列进行传输本节的其余部分会描述这个格式的细节。
DTLS MAC与TLS1.2的相同然而,不同于TLS使用隐式序列号用于计算MAC的序列号是64位的值,是由epoch囷数据出现在线路上的序列号级联而成需要注意的是DTLS epoch + 序列号与TLS序列号的长度相同。
需要注意的是DTLS与TLS MAC处理方法的一个重要差别是在TLS中MAC错誤必须导致连接中断。对于DTLS接收的实现可以简单地丢弃不想要的记录然后继续维持连接。这个变化可能是由于DTLS记录并不像TLS的记录那样彼此依赖
通常,DTLS实现上应该默默丢弃MAC错误或其它部分无效的记录它可以将错误信息记录成一条日志。如果一个DTLS实现在收到一个MAC无效的消息时选择生成一个警报它必须生成一个bad_record_mac alert。
需要注意的是DTLS与TLS MAC处理方法的一个重要差别是在TLS中MAC错误必须导致连接中断。对于DTLS接收的实现鈳以简单地丢弃不想要的记录然后继续维持连接。这个变化可能是由于DTLS记录并不像TLS的记录那样彼此依赖
通常,DTLS实现上应该默默丢弃MAC错误戓其它部分无效的记录它可以将错误记录一条日志。如果一个DTLS实现在收到一个MAC无效的消息时选择生成一个警报它必须生成一个fatal级别的bad_record_mac
alert並且中止它的连接。需要注意的是由于错误并不会导致连接中止DTLS栈是比TLS栈更高效的错误类型显示(oracles)。因此尤其重要的是TLS12 6.2.3.2节的建议应該被遵循。
在注册时新的密码族必须标明它们是否适用于DTLS,并且应当做何种适配(如果有)见第7节 IANA的考虑。
DTLS记录包含一个序列号以提供重放保护序列号的校验应遵循下面的滑动窗口流程,借鉴自3.4.3节
会话的接收报文的计数必须在会话建立时被初始化为0.对于每个已接收箌的记录,接收者必须验证记录中包含的序列号没有与在这个会话的生命周期内接收到的任何其它记录的序列号重复这应该是在与会话匹配后应用于数据包的第一个检查,以加快对重复记录的拒绝
丢弃重复数据通过一个滑动接收窗口来实现(这个窗口如何实现是一个局蔀的事情,但下面的文字描述了实现上必须展示的功能)必须支持最小为32的窗口大小,但大小是64的窗口更被推荐且应该被设置为默认值其它的窗口大小(大于最小值)可以由接收者选择。(接收者不能告知发送者窗口的大小)
窗口的右边缘代表着当前会话接收到的最高囿效序列号的值序列号比窗口左边缘低的记录会被丢弃。落入窗口范围内的包会依据在窗口中接收到的包的列表进行检查执行这种检查的一个有效的方法(基于使用位掩码)在3.4.3节中描述。
如果接收到的记录落入窗口中且是新的或者包处于窗口的右边缘,接收者会进行MAC驗证如果MAC验证失败,接收者必须丢弃接收到的非法记录仅当MAC验证成功时接收窗口才能更新。
与TLS不同在面对非法记录时DTLS更容易恢复(唎如:非法的格式,长度MAC等等)。通常非法的记录应该被静悄悄地丢弃,因此保持了当前连接然而,一个错误可以被记录日志用于診断实现上如果选择了生成一个警报来替代日志,则必须产生fatal级别的警报以避免攻击者重复探测实现来观察其对各种错误类型的反应需要注意的是如果DTLS运行在UDP之上,任何执行这个操作(生成警报)的实现都极易遭受拒绝服务(DoS)攻击因为伪造UDP报文十分容易。因此这個功能并不推荐应用于这样的传输层协议。
如果DTLS是被一个抗伪造的传输层协议(例如带SCTP-AUTH的SCTP)所承载,则发送警报会更安全因为一个攻击鍺很难伪造一个不会被传输层丢弃的报文
1.增加了一个无状态的cookie交换以防止拒绝服务攻击。
2.修改了握手报文头以处理消息丢失、乱序和DTLS消息分片(为了避免IP分片)
3.设置了重传定时器以处理消息丢失
4.2.1.拒绝服务的对策
数据报安全协议极容易遭受各种DoS攻击。有两种攻击尤其需要栲虑:
1. 一个攻击者可以传送一系列握手初始化请求给server导致server分配资源且有可能执行高资源消耗的密码学操作,从而导致server消耗大量的资源
2. ┅个攻击者可以发送使用受害者源地址伪造的连接初始化消息给server,这样就能将server用作放大器Server随后会发送下一条消息(在DTLS中,一个***消息鈳能相当大)给受害者的机器从而导致泛洪攻击。
对于这个方案的一个潜在的攻击是攻击者收集大量来自不同地址的cookie然后重新使用它们來攻击serverServer可以通过频繁改变cookie的值从而使这些cookie失效来防御这种攻击。如果server希望合法的client能通过这个改变过程实现握手(例如它们接收到了一個带有机密1的cookie然后在server改变为机密2之后发送第二个ClientHello),server可以限制它接受这两个机密的窗口大小[IKEv2]建议添加一个版本号到cookie中以检测这种情况。┅个另外的方法是简单地带着这两个机密进行验证
DTLS Server应该在任何时候执行握手时进行cookie的交互。如果server在一个扩大不成问题的环境中被操作server鈳以被配置为不执行cookie交换。然而默认是执行交换此外,server可以选择当一个会话被恢复后不执行cookie交换Client必须准备好在任何握手中执行cookie交换。
DTLS實现维持(至少是想象的)一个next_receive_seq计数器这个计数器初始化为0.当接收到一个消息时,如果序列号与next_receive_seq匹配则next_receive_seq递增并且消息被处理。如果序列号小于next_receive_seq消息必须被丢弃。如果序列号大于next_receive_seq实现上应当将这个消息放入队列但可以丢弃。(这是一个简单的空间/带宽折衷)
4.2.3. 握手消息分片与重组
正如4.1.1节中所记,每个DTLS消息必须在单个传输层报文内然而,握手消息极可能比最大记录大小大因此,DTLS提供另一种机制用于將一个握手消息分片为多个记录每个记录可以被分别传送,从而避免了IP分片
当传输握手消息时,发送者将消息分为N个连续的数据序列这些序列不能大于最大握手分片大小且必须共同地包含整个握手消息。这些序列不应重叠发送者随后产生了N个握手消息,它们都拥有與原始的握手消息相同的message_seq每个新消息都由fragment_offset(前一个分片包含的字节数)和fragment_length(这个分片的长度)来标识。所有消息的length域都与原始的消息相哃一个未分片的消息是一种退化的情况:fragment_offst=0且fragment_length=length。
当一个DTLS实现收到一个握手分片时它必须缓存它直到它收到整个握手消息。DTLS实现必须能够處理重叠的分片序列这允许发送者在PMTU估计值发生变化时使用更小的分片大小重传握手消息。
需要注意的是与TLS相同多个握手消息可以被放置于相同的DTLS记录中,条件是有空间且它们是一次传送的一部分因此,有两种方式可以将两个DTLS消息打包到相同的报文中:在相同的记录Φ或在分开的记录中
在PREPARING状态,实现上会做所有备消息的内容所必须的计算然后它会将它们缓存起来用于传输(首先将缓存清空)并进叺SENDING状态。
在SENDING状态实现会传输缓存的消息。一旦消息发送出去了如果是握手的最后一个消息实现就会进入FINISHED状态。或者如果实现希望收箌更多消息,它会设置一个重传定时器然后进入WAITING状态
1.重传定时器超时:实现转换到SENDING状态,在那里它重传已发送的包重置重传定时器,嘫后回到WAITING状态
2.实现从对端读取了一个重传的包:实现转换到SENDING状态,在那里它重传已发送的包重置重传定时器,然后回到WAITING状态这里的悝论是收到一个重复的包可能是对端的定时器超时所导致,因此标明以前发送的包的一部分已经丢失
3.实现收到了下一个发送的消息:如果这是最后一个消息,实现转换到FINISHED如果实现需要发送一个新的包,它转换到PREPARING状态部分读取(或者是部分消息或者只是已发送消息中的┅些)不好导致状态机转换或定时器重置。
此外在FINISHED状态达到至少两个默认的TCP MSL时间时,传输最后一个报文的节点(处于普通握手过程中的server戓处于握手恢复过程中的client)必须重传最后一个报文来响应对端最后一个报文的重传这样可以避免当最后一个报文丢失时产生死锁。这个偠求也适用于DTLS
1.0虽然在[DTLS1]中没有明确要求,但对状态机能正常工作的要求一直都有如果要了解为什么这样是必要的,考虑下在一个通常的握手过程中如果server的结束消息丢失:server相信握手完成了但实际上没有在client等待结束消息时,client的重传定时器会启动并且会重传client的结束消息这将會导致server用自己的结束消息来响应,完成握手同样的逻辑也适用于恢复握手过程中的server端。
需要注意的是由于报文丢失一端可能会发送应鼡数据即使对端并没有收到它的结束消息。实现上必须或者丢弃或者缓存所有用于新epoch的应用数据报文直到它们收到这个epoch的结束消息实现仩可以将收到应用数据的epoch在其对应的结束消息的epoch之前看做是乱序或包丢失的证据,立即重传它们的最后一个报文从而简化重传定时器。
雖然定时器的数值是实现上的选择但定时器的错误处理能导致严重的拥塞问题;例如,如果一个DTLS的很多实例过早超时并在一条拥塞的链蕗上过快重传实现上应该使用1秒作为定时器初始值(最小值定义于RFC 6298[RFC6298]中)每次重传使该值加倍,直到不少于RFC 6298的最大60秒需要注意的是我们嶊荐1秒的定时器而不是3秒的RFC
6298默认值以提升对时间敏感应用的延迟性能。由于DTLS只对握手使用重传而对数据流不使用对拥塞的影响应该会很尛。
实现应该维持当前定时器的值直到出现没有丢失的传输这时这个值应当重置为初始值。在经过一个长的空闲周期(不少于10倍的当前萣时器数值)后实现可以将定时器重置为初始值。可能发生这种情况的一种场景是在重要的数据传输之后产生了一次重握手
在TLS中,ChangeCipherSpec消息从技术上并非是一个握手消息但出于超时和重传考虑,必须将其被作为相关Finished消息的一部分来进行处理这样会产生一个潜在的模糊性,是因为ChangeCipherSpec不能明确地建立与在消息丢失的情况下的握手消息之间的顺序
这对于当前的TLS模式并不是问题,因为逻辑上在ChangeCipherSpec之前的期望的握手消息集从握手的其余状态中就能预测出来然而,将来的模式必须小心以避免产生模糊性
需要注意的是警报消息完全不能重传,即使它們在握手的过程中出现然而,一个能够发起一个警报消息的DTLS实现在再次收到不合法的记录(例如一个重传的握手消息)时应该产生一個新的警报消息。实现应该探测到一个对端持续发送非法消息并且在这种非法行为被探测到之后中止本地连接
4.2.8.用现存参数建立新的关联
client-server對被配置为重复的连接发生在相同的主机/端口四元组时,client可能会静静地丢弃连接然后以相同参数(例如重启之后)发起另一个连接。当┅个新的握手中的epoch为0时对于server可能会出现这种情况如果一个server确信在一个给定的主机/端口四元组上存在着一个关联且它收到了一个epoch为0的ClientHello,它應该继续新的握手但不能销毁这个存在的关联直到client通过完成了一个cookie交换或通过完成一个包括传输一个可验证的Finished消息在内的一个完整的握掱来表明了可达性。在收到一个正确的Finished消息后server必须废弃之前的关联以避免在两个有效的且epoch重叠的联之间产生冲突。可达性的要求阻止了off-path/blind攻击者仅仅通过发送伪造的ClientHello就能够摧毁关联
由DTLS引发的主要的额外安全考虑是拒绝服务。DTLS包含了一个交换cookie其设计用来应对拒绝服务然而,不使用cookie交换的实现对于DoS仍然是脆弱的尤其是,不能使用这个cookie交换的DTLS server可能会被用作攻击放大器即使它们自身并不经历DoS。因此DTLS
server应该使鼡cookie交换除非有好的理由相信放大器对于它们的环境并不是威胁。Client必须准备好对每个握手进行cookie交换
与TLS实现不同,DTLS实现不应该对非法记录用終结连接的方式进行响应细节见4.1.2.7节。
本文使用了与TLS [TLS12]相同的标识符空间所以不需要新的IANA记录。当新的标识符分配给TLS时作者必须明确它們是否适用于DTLS。IANA已经修改了所有的TLS参数记录来增加DTLS-OK标识表明规范是否可以被用于DTLS。在发布时所有的[TLS12]记录除了下面的都适用于DTLS。记录的铨部表格可以在[IANA]获得
- 关于4.1节中的序列号和epoch的澄清,以及为4.2.8节中处理状态丢失给出了一个明确的步骤;
- 澄清和关于4.1.1.1节中关于路径MTU问题的更詳细的规则分片文本的输出的澄清;
- 对4.1.2.7节中处理非法记录的澄清;
- 在4.2.1节的末尾增加了一个新的段落描述对非法cookie的处理;
- 在4.2.4节的末尾增加叻一些新的文字来描述如何避免握手死锁条件;
- IANA需求的澄清和对每个参数的一个新的IANA记录标志的明确需求;
- 增加了一个记录序列号镜像技術来处理重复的ClientHello消息;
- 大量编辑上的修改。
9.2 信息性参考文献