301海外跳转原理解析兼谈缓解假墙伪墙攻击勒索的多种技术手段(二)在上一篇文章中,我们实现了HTTP的抢答模式,避免了墙的TCP Reset。那么这次我们就来聊一聊HTTPS如何避免被TCP Reset。 我们知道,HTTPS是需要客户端和服务器之间完成TLS握手后才能收发HTTP Request和Response。然而,墙是在TLS握手时通过SNI中的域名信息进行了TCP Reset,或通过ESNI头进行TCP阻断,这时候还没有到能发送HTTP Request或Response的这个阶段,所以HTTP Response抢答模式无法应用于HTTPS。那么,我们该怎么办呢? 让我们回到TCP Reset本身——既然是TCP Reset,那么它只会对TCP协议生效。如果有一个应用层协议,其底层不是TCP呢?相信聪明的同学已经想到了,那就是HTTP 3.0(简称HTTP/3或h3)。H3的底层协议是QUIC,而QUIC是基于UDP而非TCP的。经过我的测试,发现墙现在无法识别QUIC协议,不管QUIC协议中出现任何敏感词都能无障碍过墙。这也是为什么有些网站(如v2ex)在解决了DNS污染(比如客户端主动加hosts)后,并且连接过一次(首次还是需要科学上网,原因之后会讲)后,就能关闭科学上网访问了。也就是说,使用了H3后,我们甚至不需要进行301跳转,直接就能无障碍访问服务器了(但仍建议使用301跳转,否则可能会使封锁升级,如DNS污染)。虽然H3现在仍旧处于草案阶段,但各大浏览器都已经进行了支持,而其中Google Chrome对H3的支持是最好的。 那么,如何在服务器上部署并开启H3呢?由于H3现在仍是草案阶段,所以Nginx的正式版并不支持H3,需要更换为Nginx-QUIC来支持H3。编译使用Nginx-QUIC也可以参考这篇文章。另外,Cloudflare也已经支持了H3,可以自行开启(在“网络”设置中打开“HTTP/3(使用 QUIC)”)。在Cloudflare中开启H3后,Cloudflare和服务器的通讯仍旧可以使用HTTP/2(简称h2)或HTTP/1.1,并不需要服务器支持H3,而是由Cloudflare进行协议转换。 H3主要是依赖 然而,H3是一个Alternative服务。首次访问服务器时,浏览器并不会主动使用H3,还是会优先使用H2或HTTP/1.1。当获取到 首先想到的是通过上一篇文章中的HTTP抢答模式提供 在调查和尝试了几个支持HTTPS的301海外跳转服务后,我们发现,它们根本就没有解决HTTPS的TCP Reset问题,HTTPS依然被TCP Reset了,而它们宣称支持HTTPS中301跳转的做法就是在HTTP抢答模式下加上普通的TLS服务。因为大部分网站遭遇的只是HTTP中的TCP Reset而HTTPS并不会被TCP Reset,所以只需要解决HTTP的301跳转,再加上普通的HTTPS,表面上就能同时做到HTTP和HTTPS的301跳转。而且在调查过程中我们还发现有个跳转服务主页的HTTPS也被TCP Reset了,而他们自己却对此毫无办法。那么,对于新用户访问HTTPS的TCP Reset,我们也只能止步于此,束手无策了吗?那也未必。 其实,从本系列一开始,我们就假设301跳转服务器是在国外。如果使用的是国内服务器,那么就能避免墙的识别了(因为不过墙)。但使用国内服务器(似乎)有个绕不过去的坎:备案系统——使用HTTP会提示域名没有备案,使用默认端口443的HTTPS同样会有TCP Reset。我们又该怎么办?其实,备案系统其实就是一个简化版的墙,没有TCP流量重组的功能,使用上一篇文章的抢答模式同样也能绕过备案系统。而且正是因为备案系统没有TCP流量重组的功能,我们甚至可以在TCP模式的HTTP和HTTPS中设置TCP window size(比如Linux上可以使用Geneva;Windows上可以自行编写一个反向代理,在其中设置 在讨论好HTTPS中防TCP Reset的方案后,最后让我们来聊一聊DNS污染。 其实,在撰写本文之前,我曾去尝试过几个声称可以解决域名污染的301海外跳转的服务,但无一例外都失败了,都无法解决DNS污染。然后我也去咨询了提供了这些服务的人,他们的说法大致分为两种: 那么,对于DNS污染,我们只能束手无策,或只能碰运气转移回国内了吗?那也未必。不过,由于解决DNS污染所需要的成本较高,所以这也是为什么之前H3虽然能让用户在原有域名下继续访问,我仍旧建议使用301跳转的原因。否则封锁升级为DNS污染后连301跳转都会变得比较困难了。 讲到这里,细心的同学应该已经发现,其实在刚才H3的使用方法中,已经介绍了如何使老用户在DNS污染的情况下继续进行访问的方法了。这是解决DNS污染部分问题的方法之一。那么,还有没有别的方法也能解决部分问题呢?其实,在H3的方案中,我们主要利用了浏览器的Cache中记录了H3的服务信息,来让老用户通过不同的域名或IP进行访问的。那么,浏览器的Cache中除了能保存H3的信息外,也是可以保存其他内容的。讲到这里,聪明的同学应该已经想到了。没错,就是 如果我们想从根本上解决问题,首先我们还需要了解整个DNS系统是怎么工作的: 我们知道,DNS污染是墙在海外ADNS返回正确的结果之前进行了抢答,返回了错误的结果。这样,在国内LDNS向海外ADNS查询的时候,同样会受到DNS污染,从而返回给普通用户错误的结果。那么,我们有没有办法劫持ISP的LDNS,从而让其返回我们想要的IP而不是墙返回的错误IP呢?这样,虽然DNS污染仍旧存在,但普通用户却得到了正确的IP,从而可以正常访问我们的服务器了。 讲到这里,就不得不提到2008年曾经轰动全球的DNS投毒攻击案了。在这篇文章中,Kaminsky可以修改任意LDNS中缓存的A(或AAAA以及其它)记录,虽然在经过了那次事件后这个漏洞更难被利用了,但终究无法完全修复,我们仍旧可以利用其中的原理劫持ISP的LDNS(能猜中源端口和QID就能进行劫持),将被污染域名的IP换成自己想要的IP。而且由于墙污染的TTL较小,我们也能更快地利用这个漏洞而不需要每次等待1天的时间。所以短则几天,慢则几个星期就能劫持成功。这也是现在有些价格不菲的污染清洗服务所采用的方案之一。当然,某些攻击团队也同样在利用这个漏洞就行DNS劫持,虽然导致的结果是LDNS被劫持而非墙的DNS污染,但对于普通用户所造成的结果是一致的——网站无法访问。不过,要实施这种DNS劫持需要源IP欺骗,现在能进行源IP欺骗的服务器已经越来越少了。那么我们还有没有别的方法无需源IP欺骗来劫持LDNS呢? 既然大家已经看了上面的这篇文章,那么让我们来重新细致地梳理一下整个DNS查询过程。以浏览器访问 https://www.youtube.com/ 为例: 我们知道, youtube.com 是个被DNS污染的域名,所以第5和第6步会受到墙的DNS污染,而前4步不会。第6步我们也很熟悉了,国内IP向国外IP发起查询请求时墙就会抢答 www.youtube.com 的错误A(或AAAA)记录。而第5步中,由于LDNS在国内,查询到 youtube.com 的NS记录同样会受到污染。我们同样知道,墙的DNS污染虽然成功概率接近100%,但仍有很小的概率会污染失败。那么我们能不能不停地向LDNS请求 www.youtube.com 的A(或AAAA)记录,在墙污染失败的时候,LDNS就能刷新到正确的IP地址了呢?可惜的是,LDNS是有缓存的,在缓存有效期内,不会再次向ADNS发起请求。即使在缓存失效后偶尔会由于污染失败得到了正确的IP地址,但在缓存再次失效后由于污染再次回到了错误的IP地址。所以被污染的概率仍旧接近100%。墙看上去似乎无懈可击,我们该怎么办呢? 让我们重新回到第5条,使用国内IP向 .com 的ADNS请求 youtube.com 的NS记录。以Linux为例: 在解决了第5条中的污染后,我们还需要解决第6条中的污染。而第6条中墙返回的确实是查询的A(或AAAA)记录,会被存入LDNS缓存,也就无法利用上述方法了。我们该怎么办呢?相信聪明的同学也已经想到了。没错,就是将NS记录转移回国内,这样DNS请求就不会过墙,自然就不会受到污染了。可是,不对呀?刚才不是讲过我也曾经亲自验证过,将一个被DNS污染的域名的NS记录转移回国内,等了几个月,依然被污染么?那是因为之前的测试只是将NS记录指向了国内服务器,我们并没有大量地发送NS查询请求到LDNS,所以LDNS并没有获得正确的NS记录,所以污染仍旧存在。而且,ISP的LDNS是分运营商并且分区域的。只将一个LDNS中的NS刷新到正确结果只能解决一个运营商的一小片区域中的污染,如果想要在全国范围内解决污染,需要使用大量的IP地址(因为很多ISP的LDNS限制了查询请求的发起IP只能是本地宽带用户),不停地对大量的LDNS查询NS记录,直到全国大部分地区的LDNS都获取到了正确的NS记录,才能在大范围内解决DNS污染。而且即使LDNS获取到了正确的NS记录,查询仍然要继续,因为缓存是有过期时间的。而这,也是现在很多昂贵的污染清洗服务所采用的方案之一。 关于DNS污染,我所了解到的现阶段有这些方案。如果你有别的方法,或者对本系列话题感兴趣的,都欢迎和我联系。我的联系方式为: |