跳到主要内容

代理

2023年12月23日
柏拉文
越努力,越幸运

一、认识


常见的代理有两种:普通代理(中间人代理)隧道代理

1.1 普通代理(中间人代理)

Preview

如图:代理服务器相当于一个中间人,一直帮两边传递东西,好可怜~~

不过它可以在中间可以帮我们过滤、缓存、负载均衡(多台服务器共用一台代理情况下)等一些处理

注意,实际场景中客户端和服务器之间可能有多个代理服务器

1.2 隧道代理

客户端通过CONNECT方法请求隧道代理创建一个可以到任意目标服务器和端口号的TCP连接,创建成功之后隧道代理只做请求和响应数据的转发,中间它不会做任何处理

Preview

为什么需要隧道代理呢?

我们都知道 https 服务是需要网站有证书的,而代理服务器显然没有,所以浏览器和代理之间无法创建 TLS,所以就有了隧道代理,它把浏览器的数据原样透传,这样就实现了通过中间代理和服务端进行 TLS 握手,然后进行加密传输

1.3 正向代理

工作在客户端的代理为正向代理。使用正向代理的时候,需要在客户端配置需要使用的代理服务器,正向代理对服务端透明。比如抓包工具 Fiddler、Charles 以及访问一些外网网站的代理工具都是正向代理

Preview

正向代理通常用于

  • 缓存
  • 屏蔽某些不健康的网站
  • 通过代理访问原本无法访问的网站
  • 上网认证,对用户访问进行授权

1.4 反向代理

工作在服务端的代理称为反向代理。使用反向代理的时候,不需要在客户端进行设置,反向代理对客户端透明。如 Nginx 就是反向代理

Preview

反向代理通常用于:负载均衡、服务端缓存、流量隔离、日志、金丝雀发布

二、优势


  • 突破访问限制:如访问一些单位或集团内部资源,或用国外代理服务器(翻墙)

  • 安全性更高:上网者可以通过这种方式隐藏自己的 IP,免受攻击。还可以对数据过滤,对非法 IP 限流等

  • 负载均衡:客户端请求先到代理服务器,而代理服务器后面有多少源服务器,IP 是多少,客户端是不知道的。因此,代理服务器收到请求后,通过特定的算法(随机算法、轮询、一致性 hash、LUR(最近最少使用) 算法这里不细说了)把请求分发给不同的源服务器,让各个源服务器负载尽量均衡

  • 缓存代理:将内容缓存到代理服务器(这个下面一节详细说)

三、长连接


在各个代理和服务器、客户端节点之间是一段一段的 TCP 连接,客户端通过代理访问目标服务器也叫逐段传输,用于逐段传输的请求头叫逐段传输头

逐段传输头会在每一段传输的中间代理中处理掉,不会传给下一个代理

标准的逐段传输头有:Keep-AliveTransfer-EncodingTEConnectionTrailerUpgradeProxy-AuthorizationProxy-Authenticate

Connection头决定当前事务完成后是否关闭连接,如果该值为keep-alive,则连接是持久连接不会关闭,使得对同一服务器的请求可以继续在该连接上完成

四、请求头


  • Via

    是一个能用首部,由代理服务器添加,适用于正向和反向代理,在请求和响应首部均可出现,这个消息首部可以用来追踪消息转发情况,防止循环请求,还可以识别在请求或响应传递链中消息发送者对于协议的支持能力。用法如下:

    Via: 1.1 vegur
    Via: HTTP/1.1 GWA
    Via: 1.0 fred, 1.1 p.example.net
  • X-Forwarded-For

    记录客户端请求的来源IP,每经过一级代理(匿名代理除外),代理服务器都会把这次请求的来源IP追加进去

    X-Forwarded-For: client,proxy1,proxy2

    注意:与服务器直连的代理服务器的IP不会被追加进去,该代理可能过TCP连接的Remote Address字段获取到与服务器直连的代理服务器IP
  • X-Real-IP

    一般记录真实发出请求的客户端的IP,还有X-Forwarded-Host和X-Forwarded-Proto分别记录真实发出请求的客户端的域名和协议名

五、问题


5.1 代理中客户端 IP 伪造问题以及如何预防?

X-Forwarded-For是可以伪造的,比如一些通过X-Forwarded-For获取到客户端 IP 来限制刷票的系统就可以通过伪造该请求头达到刷票的目的,如果客户端请求显示指定了

X-Forwarded-For:192.168.1.108

那么服务端收到的这个请求头,第一个 IP 就是伪造的:

预防

  1. 在对外 Nginx 服务器上配置
location / {
proxy_set_header X-Forwarded-For $remote_addr
}

这样第一个 IP 就是从 TCP 连接客户端的 IP,不会读取伪造的

  1. 从右到左遍历 X-Forwarded-For 的 IP,排除已知代理服务器 IP 和内网 IP,获取到第一个符合条件的 IP 就可以了