一个很自然的想法,使用TLS封装一个IP数据报实现一个第三层的VPN。
这种想法一定是经过了深思熟虑的,但是不幸的是,这是个错误的想法。有一篇文章《Why TCP Over TCP Is A Bad Idea》,详细解释了Why。事实上重传叠加问题是无法解决的,要知道,TCP的RTO计算是极其复杂的,影响它的因素也很多,这就是说,只要你用一个TCP封装另一个TCP,外层TCP丢包,且RTO小于内层TCP的RTO,连接就会崩溃。而以上这个条件是很容易满足的。
用TLS来封装IP数据报是对TLS的误用!SSL/TLS的初衷是提供传输层之上的安全层,本身运行了可靠的TCP上,其记录层协议封装的是应用层数据,因此,SSL/TLS是对基于TCP应用的安全增强,并不是一个通用的传输协议。之所以TLS运行于TCP之上,就是这个原因,因为应用是基于TCP的。如果你想实现一个IP层的VPN,用TLS来封装IP数据报,就相当于你将IP数据报当成了一个基于TCP的应用数据,这不正是《Why TCP Over TCP Is A Bad Idea》中描述的那种连接崩溃的场景吗?事实是,IP数据报显然不是基于TCP的应用数据。
后来出现了DTLS,显然去掉了很多约束,轻量了很多,如果非要封装使用TLS封装IP数据报,首先要想到的怎么也应该是DTLS而不是TLS。DTLS衍生自TLS,并且保留了UDP无序的语义,但是它还是从TLS继承了很多复杂的东西,本质上,DTLS也是封装应用数据的,这些应用基于UDP。循着这个思路,如果我们可以将IP数据报看作是一个基于UDP的应用数据,那么就可以用DTLS封装它了,能吗?当然能!UDP本身就是IP的第四层镜像,只是多了一个多路复用机制。使用DTLS封装IP数据报实现一个IP层VPN将会是一个不错的选择,但是还有更好的方法。
OpenVPN提供了一种更好的方式,仅仅使用TLS实现控制通道,而封装加密IP数据报的数据通道则是首选普通UDP通道。这有点IPSec的影子,不是吗?IPSec使用独立的IKE协商好SA,然后使用独立的ESP/AH协议封装加密IP数据报。其实,这才是实现IP层VPN的正确方式,本来安全参数的协商和认证/加密就是两个独立的过程,独立的过程。TLS/DTLS将这些封装进了一个会话过程中,该会话通过一个称为SSL握手的过程建立,在握手的过程中协商安全参数,握手完毕后将使用协商好的安全参数保护后续的应用数据。这种方式的不灵活性在于你无法增加自己的协商机制,除非修改TLS协议。另外作为一个TLS Record,IP数据报被封装在Application data中,外部能看到的只是一个TLS Record,中间系统很难对其进行识别和控制,也就是说,作为加密后的IP数据报的传输协议,TLS很适合,但是很难从外部去控制它,你看到的永远是一个TLS Record头,而看不到VPN协议的头。
对于IP数据报的保护,最终的思想还是IPSec的那套思想,即定义安全端点,定义安全联盟,协商安全参数,保护IP数据报,四个过程是完全独立的。虽然你可以将IP数据报看作是“应用数据”,但是它毕竟不是应用数据,TLS源自应用数据的安全需求,它针对单一应用,单独的业务逻辑可以起到很好的安全加固作用,比如实现HTTPS,比如OpenVPN的控制通道,这些都是业务单一且固定的应用,但是加密IP数据报却不适合,抛开TCP over TLS的连接崩溃问题不谈而引入DTLS,控制和传输叠加在一个会话中将会使扩展很难,比如防火墙无法区分VPN数据和其它TLS应用数据,比如无法实现组播加密,比如无法重协商单独的安全参数,同一个SSL会话无法被不同的安全端点共享...
因此, 使用TLS记录协议封装IP层VPN IS A Bad Idea,DTLS好一点,但也不绝对。真正的好的方案是,最大限度使用TLS来做控制通道协商交换安全参数,然后定义独立的封装协议来封装安全参数保护的IP数据报。例子太多了,IPSec,OpenVPN,不过OpenVPN的代码太恶心了,理解它的思想后自己写一个吧,或许会更好些。
Why 使用TLS记录协议封装IP层VPN IS A Bad Idea,布布扣,bubuko.com