Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

关于网络问题的优化

$
0
0

从实习到正式入职,宽带也从北京联通变成杭州电信,带来的影响不仅是上行带宽被强制阉割,还有出口带宽变得不如之前那么充裕了,告别了油管 1080P 的日子。之前搭建在 DO 上的 SS 已经用了两年多了,最近也开始寻觅新的 VPS 来提升网络质量。所以刚好也是一个机会,可以来总结一下关于“网络问题”的各方面内容。

众所周知,在国内经常很难正常地上网,有的时候输入了正确的网址,却莫名其妙地跳转到了另外一个网站上,有的时候访问到了网站,却发现网页下方被插入了广告,有的时候根本无法访问。

导致上面种种现象的原因有多种方面,这里主要谈论外部因素影响,层层递进地讲述几种网络访问异常的情况。分两部分,一个是 DNS 相关的,一个是 HTTPS 相关的。然后会在其中穿插讲一些客户端开发时经常可以涉及到的网络访问优化的地方,并在后面介绍几个常用的网络诊断命令,以及常见的网络代理方式。

0x01 DNS

DNS(Domain Name System):简单地说就是帮助域名找到正确的 IP 地址,类似一个电话通讯录的功能。我们在浏览器发起 Web 请求的时候,需要先做域名解析,一般先在本地的 hosts 表中查询 IP,没有查找到的话,会继续向系统设置的 DNS 服务器查找 IP,然后向指定的 IP 发起 HTTP 请求来访问 Web 站点。通常是 UDP 对 53 端口进行查询。

域名:(三级域名)www.(次级域名)antfortune.(顶级域名)com.(根域名)root.

实际上域名解析的过程是耗时的,当 DNS 服务器没有相应域名的缓存的时候,会先向根域名服务器“询问”顶级域名如何解析,然后向顶级域名服务器“询问”次级域名如何解析,最后再解析三级域名,得到确切的 IP 地址。(这里说的比较简略,实际情况更为复杂一些,具体可以参考维基百科)

正因为域名解析耗时,所以有个缓存以及过期时间的概念。域名解析的时候会优先进行缓存命中,没有命中缓存的则去向上级 DNS 服务器寻求解析。

举个例子:腾讯内网 km。实际域名持有者不是腾讯,外网访问会指向某个公网网站,而内网访问的时候,内网 DNS 服务器指向了内部服务站点。

再举个例子:DNS 优化也经常用在客户端上,尤其是一些对于网络可用性要求高的 app,比如支付宝或者微信。策略是通过 sync 或者定时轮询的方式,获取 RPC、API 域名指向的 IP 地址,访问网络的时候直接通过 IP 发起请求。这样的做法主要有三个优点:1. 避免 DNS 解析的耗时;2. 避免 DNS 劫持;3. 通过用户当前的 IP 动态分配可访问的最优节点,以提高请求效率。

DNS 劫持 case 1:某天我们在地址栏输入网址时,明明网址是正确的,却被解析到了运营商的某些网站上,甚至无法访问 case 2:一个段子,双十一的时候,我们要如何管住女朋友的双手?修改路由器 hosts 表,把 taobao.com / tmall.com 指向 127.0.0.1

这两种情况都是典型的 DNS 劫持,即 DNS 服务器返回了错误的解析结果,引导我们访问一个错误的站点。

导致 case 1 的原因通常是我们的路由器默认使用了运营商提供的 DNS 服务器。基本上每个地区的运营商都是这么搞的,不使坏的情况下,解析速度相对最优,但是问题是他们经常会使坏。解决方法也很简单,手动修改路由器或者系统设置的 DNS 服务器地址即可。

对于开发者来说其实并没有那么简单。客户确实可以通过修改 DNS 服务器地址的方式来对网站发起正确的访问,但是绝大部分客户并不具有这样的能力,尤其是在移动互联网的环境下。解决方案:HttpDNS,以及升级版本的 DNS over HTTPS。HttpDNS 简单地说就是通过 HTTP 的方式去解析域名,来避免 DNS 协议被劫持篡改,国内手淘和腾讯都采取了类似的方案。这套方案主要是使用在移动客户端上的,因为其中涉及到了请求的构造与修改。

这里涉及到一个问题:HttpDNS 通常都是访问同一个 IP 地址,那么不同地地区直连同一个 IP 不会有性能问题吗?要解决这个问题,就需要了解一个概念:Anycast(任播)。Anycast 指的是分布在各地的服务器使用同一个 IP 地址,当用户在访问这个 IP 的时候,通过动态路由协议,分流到访问最近的服务器上,最常见的应用就是 Public DNS 跟 CDN 了。如何通过动态路由协议来寻找最短路径呢?这里就涉及到了 BGP(Border Gateway Protocol,边界网关协议),相对比较复杂,具体可以看 维基百科 。

国内 DNSPod 提供了免费与商业的解决方案: DNSPod D+ HttpDNS

你也可以体验一下 Google 提供的 DNS over HTTPS 的服务: https://dns.google.com/resolve?name=www.antfortune.com

拓展阅读:

DNS 多点部署 IP Anycast + BGP 实战分析 全局精确流量调度新思路 - HttpDNS 服务详解 DNS 缓存污染

然而,即使你手动设置了 DNS 服务器,仍然存在着无法得到正确的 IP 地址的可能。原因就是著名的 DNS 缓存污染(DNS cache pollution or DNS cache poisoning)。全球互联网是通过光纤电缆联通的,国内要访问境外站点的话,不可避免地要统一走骨干网出口线路。著名的 Wall 会对 UDP 53 端口查询域名的请求做检测,如果命中黑名单的话,则返回固定的无效 IP。如果说 DNS 劫持是因为某几台服务器(节点)导致的话,DNS 污染则可以说是顶层设计(系统级别)的原因。

P.S. 不仅是 Wall,目前已知的移动的 DNS 也会自行做投毒污染。

通过 dig 命令测试一下:

~ dig www.facebook.com @8.8.8.8 ; <<>> DiG 9.8.3-P1 <<>> www.facebook.com @8.8.8.8 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25142 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;www.facebook.com. IN A ;; ANSWER SECTION: www.facebook.com. 2504 IN A 93.46.8.89 ;; Query time: 1285 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Sat Dec 3 02:26:00 2016 ;; MSG SIZE rcvd: 50

我们向 Google DNS (8.8.8.8:53 UDP)寻求域名解析,解析结果是: 93.46.8.89 。经过查询,这个 IP 是指向意大利的,明显跟 facebook 没有一毛钱关系。如果你通过 Google 来搜索这个 IP 的话,会发现这个 IP 地址加入了污染池豪华午餐中了,即 DNS 污染指向的众多无效 IP 中的一员。

正确的 DNS 解析应该是什么样的呢?我在路由器上启动了 dnsmaq,把对 facebook.com 这个域名的解析请求转发到了 OpenDNS 的 443 端口,然后执行 dig 命令查看:

~ dig www.facebook.com ; <<>> DiG 9.8.3-P1 <<>> www.facebook.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52485 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;www.facebook.com. IN A ;; ANSWER SECTION: www.facebook.com. 1827 IN CNAME star-mini.c10r.facebook.com. star-mini.c10r.facebook.com. 19 IN A 31.13.95.36 ;; Query time: 146 msec ;; SERVER: 192.168.1.1#53(192.168.1.1) ;; WHEN: Sat Dec 3 02:25:40 2016 ;; MSG SIZE rcvd: 79

这下得到了正确的解析结果了: www.facebook.com 有 CNAME 记录指向 star-mini.c10r.facebook.com. ,并解析出正确的 IP 地址: 31.13.95.36 ,IP 属于 Facebook Ireland Ltd 。

顺便一说,各大公司(Alipay、Google、Facebook 等)均有将主站域名的解析地址做 CNAME 的做法,主要的优点也是方便做负载均衡、容灾切流、最优访问策略等,读者均可以自己执行指令查看一下域名的解析结果。CNAME 相当于 bash 中的 alias,将一个域名指向另一个域名,然后再去解析 IP 地址。

除了 CNAME 之外,还有其他几种记录类型:A 记录、AAAA 记录、NS 记录、MX 记录、TXT 记录等,不再一一展开。

回到上述话题,我们直接对 31.13.95.36 这个 IP 发起 HTTP 请求,结果是仍然无法连接上网站。那么问题来了,既然我们能够通过非 UDP 访问 53 端口的方式来解析域名获取到正确的 IP,为什么我还是无法正常访问到我想要访问的网站呢?

IP 封锁

这是 DNS 污染的进阶方案,直接将 IP 给干掉,这样基本上就彻底无法访问了。

对刚才正确解析出来的 IP 31.13.95.36 执行 traceroute 命令查看请求链路:

~ traceroute 31.13.95.36 traceroute to 31.13.95.36 (31.13.95.36), 64 hops max, 52 byte packets 1 openwrt (192.168.1.1) 1.965 ms 0.923 ms 0.837 ms 2 183.128.104.1 (183.128.104.1) 2.917 ms 5.374 ms 3.081 ms 3 220.191.158.29 (220.191.158.29) 1.999 ms 3.252 ms 2.259 ms 4 61.164.22.149 (61.164.22.149) 4.790 ms 220.191.143.161 (220.191.143.161) 2.672 ms 61.164.22.141 (61.164.22.141) 7.740 ms 5 202.97.92.41 (202.97.92.41) 6.699 ms 202.97.26.13 (202.97.26.13) 12.492 ms 202.97.92.41 (202.97.92.41) 8.768 ms 6 202.97.33.74 (202.97.33.74) 8.739 ms * 1193.326 ms 7 * * * 8 * * * 9 * * * 10 * * *

traceroute 命令用于跟踪请求数据包的路由路径,可以看到对该 IP 的请求,在走到 202.97.33.74 之后,基本就是 timeout 了,该 IP 所在的位置是上海电信。

0x02 HTTP / HTTPS

HTTP 就不说了,让我们来简单聊聊 HTTPS。最近也有不少关于 HTTPS 的大新闻,比如苹果要求所有的 App 的网络请求都要升级到 HTTPS,否则可能不能过审。

大家都知道 HTTPS 因为是加密通信,所以比 HTTP 来得更为安全,那么它又是如何进行加密的?

HTTPS = HTTP + TLS。SSL 已经退出历史舞台,说 SSL 的时候通常是指 TLS。

运作流程可以查看下图:


关于网络问题的优化

具体说下其中的几个环节:

证书:

通过第一次握手建立上连接之后,服务端会向客户端发送一个证书(包含网站地址、加密使用的公钥、证书颁发机构信息)。客户端会对证书的有效性进行校验。通常,操作系统中都会内置一些可以信任的证书,证书的信任关系是嵌套的,比如 A 信任 B,B 信任 C,那么 A 就会信任 C。除了根证书之外,任何一个证书都需要上一个证书的信任。因此,通常来说我们的 HTTPS 证书都需要由某几个 CA(Certificate Authority,证书授权中心)来授权颁发,以被客户端能够信任。

非对称加密:

客户端使用服务端发来的公钥对本地生成的一个随机数做加密,并带上校验值一起发送给服务端。服务端使用私钥进行解密,并对校验值进行校验,确定随机数的是否正确。

对称加密:

由于 RSA 的运算效率相当低,所以通常并不是整个通信过程都使用非对称加密的方式的。非对称加密主要运用在握手环节的获取密钥的地方,其余大部分信息传输都是对称加密。整个 HTTPS 的握手环节,任何一个步骤出错了,都会直接中止连接。

HTTPS 也并非就是绝对的安全,14 年爆发的 Heart Bleed 漏洞(虽然缺陷是 OpenSSL 的实现导致的,但是绝大部分 TLS 协议都是基于 OpenSSL 来实现的)仍然让人心有余悸,许多知名的大网站都中了招。所以,除了将站点升级到 HTTPS 之外,也需要经常关注相关的安全新闻,即时堵上潜在的漏洞。

这篇文章仅对 HTTPS 的几个关键环节进行简要叙述,如果你希望能够对 TLS 的具体协议能够有深入的了解的话,可以阅读这篇文章: TLS 协议分析与现代加密通信协议设计 。

HTTP 劫持

还是从一个常见的例子来讲,如图:


关于网络问题的优化

WTF?我不是正常访问一个技术站点吗?咋植入了联通的广告呢?而且一下子把我整个屏幕给覆盖了。

这个是我们日常用手机上网的时候经常会遇见的事情:运营商劫持投放广告。这种 HTTP 劫持甚至还出现过导致客户端 crash 的问题,你能够想象一个正常的 JSON 请求被塞入了广告 JS 代码是多么恶心的事情吗?

我们前面已经讲到了 HTTP 不安全,运营商可以直接在目标网站的 HTTP Response 里直接塞入自己的广告代码,导致该现象的发生。通常来说,这个植入仅会针对 Response Header 中 content-type 为 text/plain 的 HTTP 请求。如果无法升级 HTTPS 的话,一个简单

Viewing all articles
Browse latest Browse all 12749

Trending Articles