写在前面

春节将至,这一年载满了汗水,辛劳;稍作停顿,你我来年将奋力向前。

疫情当下,这一年历尽了离别,牵挂;光阴飞度,星河旋转,云中遥寄锦书来。

一千年前,车马劳顿,锦书难托。

一千年后,指尖点点,心意相通。

庆贺中通“宝盒”即时通信服务(IM)从待字闺中到风光出阁,亦庆贺宝盒SDP正式上线。

不仅有VPN

大家准备好VPN,请提前检查是否可以正常连上公司内网......

有紧急任务了,赶快登上VPN看一下!

这么多年VPN这笨重的身影陪伴大家走过了多少个焦急的夜晚,白天。

VPN如此有用,但VPN又是如此的繁琐,让人爱恨不能。

时至今日中通人终于多了一个新选择,宝盒SDP,她将和VPN一道为中通人提供更加强力的线上办公支持。

为什么

中通自从有了宝盒这款应用之后,很多事情有了新的解决方案,新的思路。

放假了,有个紧急事情需要处理一下,要怎么办?

打开VPN,输入账号,没有验证码,验证码在宝盒里;打开手机宝盒,拿到动态验证码,手动输入进去。还没完,登录完VPN,然后再打开需要访问的web应用,重复上一步操作,输入账号,查看宝盒验证码,登录......

好慢,我很着急啊,能不能再快点?以前不能,现在可以了,因为我们有了宝盒SDP。打开PC宝盒,一步到位,不需要再登录VPN了,不用每逢放假检查VPN了。给用户提供方便,就是我们做产品的初衷!

除了方便,还可以做得更多。我们能够追踪到用户访问了什么资源,用了多少宽带,可以完全的,全方位的做用户访问鉴权。这相比于之前的VPN,更安全,精细了!有了这些基础设施,我们就能够拿到很多之前没法拿到的第一手数据,而使用这些数据,我们可以逐渐迭代出一个牢不可破的安全堡垒。

VPN往后的趋势

VPN虽然用的人很多,但由于工作领域的原因深入了解过的人可能并不多。借着这篇文章浅谈一下VPN这种技术。

VPN是虚拟专用网络的简称,从实现上可以简单理解为VPN建立了一个虚拟网卡,用户网络上的所有流量都会被强制接管,此时用户的IP就变成了VPN的IP。从技术原理上来说VPN具有一定优势,它能真正实现全局代理。用VPN的同学可以查看电脑的网络适配器,一般而言里面会有VPN创建的专用适配器。

VPN之所以安全是因为在公用网络上建立了专用网络,全程采用加密通讯。用户接入VPN,其实就是接入了一个专有网络,你的网络访问都要从这个出口出去,虽然可以通过一定规则过滤掉部分流量但是可以操作的空间其实很小。

目前主流的VPN协议,PPTP、L2TP、OpenVPN和SSTP都跑在第二,三层即网络层和数据链路层,由于处在网络模型的较低层次所以VPN可以接管全部的流量,但同时也是由于这个原因VPN没有办法做较精细的权限控制。

企业网络信任拥有正确VPN凭证的人,认为拥有这些凭证就应赋予访问权限。但若该VPN用户恰好是恶意用户或盗取了凭证的未授权用户,那就成问题了,而且是VPN无法妥善解决的固有问题。攻击者进入内网后基本就畅通无阻了,而且很多企业的内网服务都是弱密码,甚至没有密码,这种危害无疑是巨大的。

这些年在安全领域中,软件定义边界 (SDP)逐渐崭露头角,虽然业界目前并没有完整落地的技术实现,但是理论模型却也渐渐清晰。

SDP不会因为采用了传输层安全就认为加密隧道是安全的,所以SDP往往和 “零信任” 是一对双胞胎。我们在前面提到过VPN的安全保障是基于通信加密的,所以从这些角度来说,VPN并不安全。

典型SDP架构中,每个连接要经过多点验证和检查,以帮助保障真实性和限制风险。通常SDP模型中设置有定义资源访问策略的控制器,规定哪些客户端可以连接并访问不同资源。网关组件则帮助导引流量到正确的数据中心或云资源。最后,设备和服务使用SDP客户端通过控制器连接并请求资源。当然,有些SDP实现了无客户端式。

零信任或SDP本身是想要消除内外网这种边界的,这样我们便不需要通过代理或VPN接管流量,毕竟VPN或者代理只是为了打通不同的网络边界。但是从现实的角度来看消除内外网边界难度很大,任重而道远。代理和SDP理论相结合的方式更容易推广部署。

从应用场景上来说,VPN作为企业内网访问的桥梁是非常适合采用SDP架构的,借助于SDP中的零信任理念,对每一个连接进行验证和检查,这样我们就可以在不改变数以千计的内网应用的前提下加强安全管控与权限校验。但现实往往存在困境,这种困境或许正是SDP并未大规模流行的原因之一。目前并没有很好的技术手段能够把用户流量引导至SDP客户端,这里的引导指用SDP客户端代理用户流量,SDP代理用户流量要满足一定条件,即我们能够从每个连接中分析出用户的意图;比如某用户发起一个TCP连接,实际这个连接从效果上来说是个http请求,那么这个连接就要包含域名信息,这样我们的SDP控制器才能够对其进行验证和鉴权。

从VPN的技术方案来说是可以满足把流量引导至一处统一处理的,当然这里未必就是引导至SDP客户端,它也可以是云上的一个服务,但由于VPN工作在网络模型的2,3层,能够提供的信息偏少,很难据此设计出一个强大的权限控制器,而且VPN代理的是全部流量,噪点过多,实际开发难度偏大。所以SDP并不适合采用像VPN那样创建虚拟网卡的方式接管用户流量。

如何代理用户的网络流量呢,目前基本没有办法重复造轮子,必须充分考虑现有技术方案,从操作系统支持的代理方案中选择一种能够满足SDP架构需要的。经过调研,socks5作为一种代理协议,主流操作系统支持良好,简单轻量,而且协议本身包含域名信息,可以自定义dns解析,而且可以配合PAC规则过滤非内网请求,从实际效果上来看与SDP的架构较为契合。

为了应对日益严峻的安全挑战,中通安全团队基于SDP理论打造了一款VPN的替代产品。

如何实现

中通普及了宝盒这款应用,在整个SDP方案中宝盒充当了SDP客户端的角色。它同时也是一个正向代理,当我们通过宝盒访问内网应用时,操作系统会将流量转发至宝盒内置的代理模块,宝盒代理模块会对流量进行重新封包加入用户信息和认证信息,转发至ZFE代理服务,ZFE是中通零信任网关的简称,目前已经在中通全面推广。ZFE拿到请求后会对连接进行验证和鉴权,如果是一个HTTP请求还会进行DNS解析。一个请求只有通过校验才会放行至下一跳。

图1. ZFE SDP架构图

ZFE作为中通所有应用的公网流量入口它集成了非常多的特性,根据部署的形式的不同,它既可以作为SDP的代理服务,也可以作为零信任网关。整个链路完全中通自研,可以全程无死角控制流量,实时阻断请求,分析用户行为。

将流量转发至宝盒

这一步我们采用的是SOCKS5协议,它是SOCKS协议的最新版本。

SOCKS是一种Internet协议,通过代理服务器在客户端和服务器之间交换网络数据包。SOCKS5可选地提供身份验证,以便只有授权的用户才能访问服务器。实际上,SOCKS服务器将TCP连接代理到任意IP地址,并提供UDP包转发的方法。

采用SOCKS5协议的好处是,可以方便动态的设置代理,无论是操作系统还是浏览器都提供了相关的API。我们可以实时的更改代理配置,另外一方面SOCKS5可以采用PAC文件(代理自动配置)自动过滤不需要采用代理的服务,同时PAC也支持容错机制,当一个代理服务节点无法响应的时候,可以自动平滑迁移至健康节点。

Windows平台我们可以采用系统API设置全局代理或PAC代理

[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]publicstaticexternboolInternetSetOption(IntPtr hInternet,int dwOption, IntPtr lpBuffer,int dwBufferLength);

[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]privatestaticexternboolInternetQueryOption(IntPtr hInternet,uint dwOption, IntPtr lpBuffer,refint lpdwBufferLength);

在Windows平台下有一点需要注意只有采用pac模式下使用的才是SOCKS5协议,如果设置的是全局代理那么此时会使用socks4协议。

基于Chrome的浏览器或像Electron这样的跨平台框架我们可以采用启动时加入命令行参数的形式设置代理

--proxy-server="socks5://myproxy:8080"

--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE myproxy"

--proxy-pac-url="http://localhost:8080/pac"

Linux和Mac等Unix Like的系统我们可以采用设置环境变量的形式设置代理

export https_proxy="socks5://myproxy:8080"

export http_proxy="socks5://myproxy:8080"

对于使用SOCKS5的代理程序,如V2ray,Trojand等,在网络层级中同属会话层,所以会有很多流量都无法代理,一个常见的例子就是开了全局代理也不能通过代理使用ping和trace这些ICMP指令。不过VPN并没有这个问题,因为VPN工作在2,3层。我们的宝盒使用的SOCKS5协议,所以同样也有此类问题。

SOCKS5并不会要求应用程序必须使用代理,比如linux下即便通过环境变量设置了SOCKS5代理,对一些程序来说依旧不会走代理。这是因为虽然系统设置了此代理,但其实仅仅只是一个环境变量而已,他只是一个标准。具体是否实现此代理要靠应用程序自己实现。Windows不同于Linux提供了较为丰富的控制API。

如果想要在Linux下实现全局代理,可以采用VPN类似的方式创建虚拟网卡由虚拟网卡接管流量,或者使用Netfilter(Iptables),把所有需要代理的流量转发至代理服务。

从宝盒到云上的代理服务

这一段是整个流程中最复杂的,我们需要设计通讯协议(ARCHER)和加解密方案。

从宝盒到代理服务这一段采用完全量身定制的通讯协议,SOCKS5协议和认证信息被完整的封进了这个自定义协议里面。该协议在传输过程中采用两段式加密,这有点像HTTPS的握手流程,采用非对称加密传输对称加密的密钥。采用两段式加密的主要目的是在兼顾性能的基础上防止有人拦截分析流量内容。

客户端连接到代理服务,并发送一条认证消息(单位为字节)

  • Version:协议版本

  • Nmethod:加密方式长度

  • Reserved:保留字段

  • Methods:加密方式

  • Ntoken:用户身份凭证长度

  • Token:用户身份凭证

代理服务器收到认证后发送应答消息

  • Version:协议版本

  • Nmethods:加密方式长度

  • Reserved:保留字段

  • Methods:加密方式

  • Command:给客户端的指令,0 成功、1 认证失败、2 未知操作、3 无权操作

以上为ARCHER报文格式,仅供演示使用

经过该协议封包后的流量会采用一段加密隐藏协议报头信息,然后再使用协议约定的二段加密算法对报文中携带的用户SOCKS5流量加密。

代理服务Server端通过约定的一段加密算法解包加密报头,获取二段加密的加密算法以及用户身份凭证。

注意此时还没有用户实际要访问的服务的域名信息,我们还必须进一步解包SOCKS5流量,从中取出域名。对于SOCKS5协议而言,报文携带域名信息主要是为了dns解析之用,我们之所以选中SOCKS5作为我们SDP客户端的协议载体也恰恰看重的是报文中携带域名,由此我们可以做出基于资源(域名)和身份的认证系统。

二段加密算法用于解密用户SOCKS5流量,SOCKS5协议中包含用户的实际请求流量,这一阶段的流量往往会比较大,所以对于性能会有一定的要求,在文章后半段会重点讲一下。

在整个过程中出现的认证和鉴权失败的错误信息都会由服务器端通过ARCHER协议返回给客户端方便定位错误,所以我们在协议中定义了一个Command位,以标志出各种错误。

有一点需要强调:只有操作系统到宝盒本地代理这一段采用SOCKS5协议是必须的,而从本地代理到服务器端这一段并非一定要采用SOCKS5,只要满足安全需要理论上可以采用任意格式。我们的方案在传输这一块对SOCKS5协议进行了二次封装,所以在解包时需要先解自定义协议ARCHER,再解SOCKS5,这样才能拿到全部的信息。这样做的好处是客户端会轻量一点,否则需要在客户端处理整个SOCKS5协议,然后再按照特定格式对报文进行二次封装,这非常不便于宝盒的快速迭代。

一段加密

一段加密用于报头加密,其目的在于混淆协议,让攻击者无法分析出流量特征,进而采取攻击措施。本文不再赘述细节。

二段加密

HTTPS之所以没有全程采用非对称加密正是因为性能损耗过大。ARCHER作为一个代理协议如果性能不行,延迟过大,对用户来说将毫无体验可言。

实际的加密方式可由本地代理和服务器端协商产生。报头中的Methods字段为支持的加密方式,服务器端回包的报文中的Methods字段为协商使用的加密方式。我们默认采用了CHACHA20-POLY1305加密方式。

密码学是一个较为高深且晦涩的领域,之所以选择CHACHA20-POLY1305作为默认加密算法是因为在有限的渠道内,通过对比发现其性能强大,且能满足我们的安全需要。

CHACHA20-POLY1305是一种AEAD算法。AEAD算法可以追溯到2008年,AEAD的全称是Authenticated encryption (AE) and authenticated encryption with associated data (AEAD, variant of AE)。也就是带附加数据的加密和验证算法。

很多涉及IO的系统收发数据的时候一般会加上一些校验码(MAC),以便检测IO错误。而对外的SOCKET里,这个校验码还有一个功能是挡掉一些不正常的数据。如果这时候如果我们的数据需要带上加密的话,那就是AE了。然后AEAD就是在AE的基础上,增加一些自定义数据,用于防止猜解。

简单说下MAC (Message Authentication Codes),MAC 核心是带秘密密钥的Hash函数。消息的散列值由只有通信双方知道的秘密密钥K来控制。此时Hash值称作MAC。MAC值用于鉴别消息在传送途中是否被篡改。当消息被发送者发出之前,应由发送者产生MAC;接收者收到消息后,将重新计算MAC值,若相同,则表明消息未被篡改。

CHACHA20-POLY1305是由CHACHA20流密码和POLY1305消息认证码(MAC)结合的一种应用在互联网安全协议中的认证加密算法,由Google公司率先在Android移动平台中的Chrome中代替RC4使用。具有算法精简、安全性强、兼容性强等特点。

常见的 AEAD 算法有

  • AES-128-GCM

  • AES-192-GCM

  • AES-256-GCM

  • CHACHA20-POLY1305

在具备AES加速的CPU(桌面,服务器)上AES系列算法一般具有更高的性能,但是纯软件实现时CHACHA20-POLY1305表现更好。

目前在https中也已经大量使用了该算法,可以通过nginx开启该算法支持。

从代理服务到目标服务

只有宝盒中的本地代理到服务器端这一段是加密的,从服务器端的代理服务到目标服务这一段是原始的流量。假如用户访问的是百度,抓包本地代理到服务器端这段流量你能看到的只有一段乱码,而抓包服务器端到目标服务这一段你将看到真实的流量,如果是一个HTTP的服务你将直接看到请求内容。

服务器端代理服务会把目标服务返回的真实流量通过协议转化和加密处理后再返回给宝盒本地代理,本地代理解密后会转化成原始SOCK5流量吐给操作系统,经过一系列复杂的转化与加解密,此时用户终于能正常访问内网的目标服务了。

在这个环节中有一个很重要的细节,如果我们要对请求做更细粒度的鉴权,比如我们想控制某个用户只能访问特定URL,我们想让高风险应用自动接入SSO,我们想要临时封禁某个用户等等,这些需求单纯的代理服务是无法实现的,因为代理服务工作在4层无法解析HTTP流量。但是ZFE可以实现,代理服务是ZFE的一个功能模块,ZFE一个更重要的角色是反向代理,ZFE内部集成了规则引擎可以对请求流量和响应流量做更细粒度的控制。

在之前的文章中我们有介绍IAM在中通的实践与落地,虽然本文中鲜有提及IAM,但IAM的身影确是无处不在。IAM是整个架构中权限与认证的核心所在,它是大脑负责分析与决策,ZFE是四肢忠实的执行了大脑颁发的策略。

人—应用—权限

中通SDP支持自定义DNS解析,也就是说可以在不变动服务真实域名的的前提下灵活的给服务起别名。这在有的场景下很有用,比如借助该特性我们可以把服务划分成各类APP,然后通过APP NAME或APP ID访问服务。此时如果把人和权限加进来就是一个完整的权限控制链条了。

自定义DNS

这里其实就是一组映射关系,KEY可以是域名(支持通配),可以是IP,甚至可以是任意的字符串。VALUE为该服务的地址。通过这组映射我们就建立起了从名称到服务的关联。

图2. 配置DNS解析

设置APP域名或别名

建立了从名称到服务的关联关系之后如何通过名称找到对应的应用呢?中通SDP同样支持名称和APP的关联。我们可以给APP关联域名,别名,以及任意的我们希望能够关联到该APP的字符串。

设置人的访问权限

有了服务,应用,最后一步就是人如何访问这些应用了。

图3. 配置人在指定APP的权限

整个过程概括起来:

用户发起请求,SDP根据别名找到对应的APP,然后SDP权限控制器判断用户是否对该APP具有访问权限,如果满足权限要求,则进行DNS查询找到真实服务地址完成访问。

SDP的默认规则会拒绝所有未经认证和授权的连接请求,这就是通过设置别名的方式实现了SDP的域名隐身功能。

以SDP的角度来看

SDP对外提供零可见性和零连接,只有在端点证明他们可以被信任之后才可以建立连接,允许合法流量通过 。

ZFE代理模块在接受客户端连接时会进行身份认证,只有受信任的用户才能建立连接。

SDP的安全模型融合了设备身份验证、基于身份的访问和动态配置连接三大组件,为了阻止大部分类型的网络攻击,类似像DDos攻击、中间人攻击、服务器查询、OWASP、ATP等。SDP要求用户拿出多种身份验证信息,比如时间、位置、终端情况等等,用以证实该用户的身份,或者验证用户能否被信任。

IAM零信任架构提供了全方位的身份认证与权限控制能力,为整个链路提供决策依据。

一旦用户可被验证,我们就可以确信用户是谁,SDP在用户和所请求的资源间创建一条安全的加密隧道,保护二者之间的通信。而且网络的其他部分则被设为不可见。通过隐藏网络资源,SDP可减小攻击界面,并清除用户扫描网络和在网络中横向移动的可能性。

携带身份与设备信息的请求连接,以及可以自定义的两阶段加密通信方案,配合IAM零信任体系全方位提升安全检测处理能力。

简单将sdp的工作方式进行概括就是:

  • 将所有服务置于“拒绝所有”的SDP网关后方

  • 打开防火墙建立连接之前先认证设备上的用户

  • 使用动态防火墙机制,当DDos攻击发生时允许SDP尽可能快的丢弃攻击数据包

  • SDP通过使目标服务器对未授权设备不可见来预防攻击

我们这套方案采用了 客户端-网关 的模式整合了中通现有的技术方案,如其中的IAM和ZFE,感兴趣的朋友可以浏览之前的文章(参考助力中通零信任安全架构落地的现代化IAM平台基于PBAC模型构建零信任IAM平台中通零信任安全代理ZFE)。

图4. SDP的4种部署方式

在SDP的架构中也支持无客户端模式,例如用户可以利用SSO动态添加被访问服务的防火墙规则,以达到允许指定用户访问的目的。但是这种方案需要实时维护大量的防火墙规则成本过高,缺乏灵活性。

写在结尾

这套方案同样存在不足之处,由于无法代理全部的流量,VPN在某些场景下还将会继续发挥作用,例如需要在终端进行的一些操作,远程协作等。不过鉴于中通目前大多采用B/S架构,主要以WEB流量为主,该SDP架构能够满足多数使用场景。

做基础架构很多时候,投入多,见效慢,瞎折腾,有时候也会被误解而遇到巨大的挫折。但是一旦坚持到大厦竣工所有的努力形成合力时便会有一种拨云见日,一览群山之畅快。

相关参考:

如何通过IAM打造零信任安全架构:

https://zhuanlan.zhihu.com/p/145273883

socks5协议:

https://datatracker.ietf.org/doc/html/rfc1928

SDP vs. VPN - What"s Best for You?:

https://www.electric.ai/blog/sdp-vs-VPN

SDP vs. VPN vs. 零信任,后来者居上?

https://www.sdnlab.com/24709.html

Virtual private network:

https://en.wikipedia.org/wiki/Virtual_private_network

声明:本文来自中通安全应急响应中心,版权归作者所有。文章内容仅代表作者独立观点,不代表安全内参立场,转载目的在于传递更多信息。如有侵权,请联系 anquanneican@163.com。