1

温故而知新之 https proxy

 1 year ago
source link: https://liudanking.com/beautiful-life/new-learn-from-old-https-proxy/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

温故而知新之 https proxy

发表于2022-07-31

周六昏昏欲睡的下午,顺手用 goproxy 写了个小工具。功能部分不到两个小时就搞定了,但是在处理 https proxy 部分,希望实现一个自定义feature时,调试了挺长时间。这大大打击了自诩可以手撕 https/tls 的自我信心😝。于是顺手看了一下这块的实现部分。

原理上,https proxy 的处理,都是以客户端 CONNECT 请求开始,后续的请求都是通过这次建立的连接进行 req-rsp 交互。一句话就能讲完,很简单,对吧?对也不对。正确的部分在于,原理的确就是这样的,但是如何使用这个连接,以及如何处理其中的安全问题让这一块有很多细节需要考虑。所谓魔鬼在细节中,这也是这块最有意思的地方。

以 goproxy 这块的实现为例,通过 CONNECT 建立连接以后,请求的的交互主要支持4种方式

  • ConnectAccept
  • ConnectHijack
  • ConnectHTTPMitm
  • ConnectMitm

ConnectAccept 是最基本的方式,只负责在 tcp 层建立远端和客户端的连接,这个连接具体怎么用,由客户端自己与远端交互决定。各个平台、各个客户端都支持这种方式,基本上没有兼容性问题。

ConnectHijack 与后面的两种方式本质上同一种类型,都可以认为是 Hijack 类型。这里涉及一个很重要的概念 Hijack, 这个在 golang 标准库中有非常准确详细的解释,搬运如下:

// Hijack lets the caller take over the connection.
// After a call to Hijack the HTTP server library
// will not do anything else with the connection.
// It becomes the caller's responsibility to manage
// and close the connection.
// The returned net.Conn may have read or write deadlines
// already set, depending on the configuration of the
// Server. It is the caller's responsibility to set
// or clear those deadlines as needed.
// The returned bufio.Reader may contain unprocessed buffered
// data from the client.
// After a call to Hijack, the original Request.Body must not
// be used. The original Request's Context remains valid and
// is not canceled until the Request's ServeHTTP method
// returns.

也就是相较于 ConnectAccept, proxy 不再是中间的小透明,而是可以接管连接,在中间实现一些自定义有意思的功能,这也是 MITM 的基石。所不同的是:

  • ConnectHijack 要求在业务自己在应用层实现这块逻辑,优点就是一切尽在掌握,可以实现很多有意思的功能。
  • ConnectHTTPMitm 是一种 https 降级为 http 的一种实现。也就是 https 通过这个 proxy 后,都被降级为 http 请求与远端交互。优点是可以 offload TLS 这层的加解密和签名开销,但是完全没有安全性。因此,这种一种古老的方式已经不被绝大部分 client 支持了。
  • ConnectMitm 则是一种经典实现,把客户端的 https 请求在中间做中转,然后还是以 https 的方式发送到远端。这是被client广泛支持的方式,因此兼容性较好。

需要说明的是:

  • Hijack 类型都依赖CA证书,这也是为什么你手机、电脑设备里面的CA根证书很重要,不要随便信任和安装来路不明证书的原因。
  • goproxy 在 ConnectHTTPMitmConnectMitm 的实现中,都会再次调用 filterRequest 执行 OnRequest 的 handler, 因此要在你的 request handler 中识别和处理这种经过转换的请求,否则会出现 loop 以及请求失败的情况。

从原理到实现,基本就拆解完了。其实也没有什么高深的部分,正如很多东西,不过是温故而知新,进一寸有一寸的欢喜。

–EOF–

版权声明
转载请注明出处,本文原始链接

此条目是由daniel发表在Beautiful LifeGolangSiteLog分类目录的。将固定链接加入收藏夹。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK