浏览器输入URL之后都发生了什么?

Posted by Haiming on April 21, 2020

先做个假设:

  • 一个 Chrome 浏览器
  • 一台 Linux 服务器
  • 发起 HTML 请求
  • 不考虑任何缓存和优化机制
  • 采用 HTTP/1.1 + TLS/1.2 + TCP 协议

1. URL解析

HSTS

由于安全隐患,会使用HSTS强制客户端使用HTTPS来访问页面。

HSTS是可以防止中间人劫持的一种有效方式。

参考资料:https://www.barretlee.com/blog/2015/10/22/hsts-intro/

一般而言,人们访问网址时候都没有主动加入https的头部,比如taobao.com,那么实际上是默认访问http://www.taobao.com 的,之后再302到https的页面。那么中间人就可以利用这一点来做攻击:

首先,浏览器使用80端口来请求服务器,此时劫持者模拟正常的https流程使用443端口来向taobao的服务器请求数据。之后浏览器会认为自己连接上了一个正常的服务器(其一直使用的是80端口,没有使用https,相当于中间人用https通信之后再用80端口转发回去),那么中间人就可以截取到用户的所有信息。

而HSTS的作用,就是在这种情况下强制用户使用https://taobao.com 这个地址来做访问,那么自然就劫持不了80端口,中间人也就没法做手脚了。

2. DNS查询

浏览器首先会试图查找缓存之中的地址,如果缓存之中拿不到,那么就会去DNS服务器之中获取。

DNS查询之中有递归查询和迭代查询。迭代查询是A–>B–>C–>D 这样的一个顺序,然后从D开始,再D–>C–>B–>A 这样的一个反向链条。但是递归查询不同,是从根目录开始,例如对 taobao.com,是先查询.com 域名下面的DNS服务器C,然后再去DNS服务器C来拿到最后的真正IP地址。

img

2.1 DNS劫持和HTTP劫持区别

DNS劫持是直接劫持DNS地址,比如本来你要访问www.google.com, 我给你返回的是 www.baidu.com 的IP地址,那么你就会在浏览器的地址栏看到 google,但是实际访问的全是baidu的内容。

HTTP劫持之中对于IP是没有改变的, 但是会截取HTTP的报文内容,然后做修改之后抢先回包,比如:

preview

3. TCP连接

3.1 应用层:发送HTTP请求

报头,传输内容和请求正文。

3.1.1 重定向

重定向有301,302和304。 如果浏览器收到了服务器这边的HTTP回应,那么可能为一个重定向连接。301是永久重定向,意味着之前的资源已经不可访问了,搜索引擎抓取的时候也会变成重定向之后的网址。但是302是暂时重定向,意味着之前的资源还在,还可以访问。304的话是浏览器带上某些条件然后访问服务器,如果服务器发现文件当时还没有被改动,那么就会返回304,浏览器就可以直接去本地缓存之中拿取。

304的案例:

img

传输层:TCP传输报文

TCP三次握手

preview

可以看到在三次握手之后还有TLS套件的四次握手部分。其中TLS的四次握手,前面两次是明文传输,用来规定双方的加密套件,随机数,等等。后两次的过程之中,是客户端先使用对方的证书进行加密一个自己选择的密钥,然后发送给对方。服务端解密,并且使用这个密钥发送Finished 报文,这样就完成了所有的握手协商。

SYN洪泛攻击和解决方法

SYN洪泛攻击为:

攻击者利用三次握手的条件,在第一步发送很多请求,但是在服务器返回请求之后不返回ACK,那么服务器这边会维持一个半连接队列,如果是一直攻击,那么这个队列就会被占满,这种情况下正常的业务就只能处于等待状态。

防范措施:

  1. 减少timeout等待时间
  2. 使用SYN cookie,如果短时间收到某个IP的巨量请求就丢弃
  3. 使用一种算法,不保持半连接队列,而是对每一个请求返回的SYN上面生成SYN cookies。这种cookies不需要保存,而是可以通过计算来算出其是否合法,虽然有一定的错判概率,但是仍然可以过滤大部分攻击请求。

链路层:以太网协议

ARP攻击

ARP攻击即局域网之中不断向外广播ARP包,那么让所有的IP地址都对应到自己主机的mac地址来,那么就会截取到别人的通信内容。

服务器处理请求

一般而言,服务器之前要再有一关代理,将请求反向代理到真正的服务器之上,比如nginx。那么什么是反向代理,什么是正向代理呢?反向代理是给被访问的资源做代理,正向代理是给访问的资源做代理。

然后代理服务器会按照规则将请求重写到Restful风格的URL之上。在之后就是spring截取URL,并且在其中进行处理,高并发就Redis做缓存,内部复杂通信就是RabbitMQ这一套了。