mitmproxy实践教程之调试 Android 上 HTTP流量

之前写了一篇博客介绍了mitmproxy,不过有些同学对这个工具到底该怎么使用还是有点不清楚,于是自己花了一天时间把自己对这个工具的理解和使用过程进行了一番整理,形成了这篇文章。接下来我就以一些简单的场景来说明mitmproxy的用法。

实践环境

iMac一台、华为B199(Android 4.4)手机一部,这两者都连着同一个wifi。mitmproxy安装版本为0.11.3。iMac的ip地址为:192.168.0.104

mitmproxy安装与设置

    1. 下载mitmproxy。推荐下载二进制安装包(当前版本为0.11.3),因为使用pip安装会由于墙的原因安装失败。下载成功之后解压,便可直接点击名为“mitmproxy”的文件了。
    2. 在iMac上运行和设置mitmproxy。由于直接点击运行是没有设置mitmproxy参数的,所以我们需要在命令行里面输入mitmproxy进行设置:
      $ [YOUR_DOWNLOAD_PATH]/mitmproxy -b 192.168.0.104 -p 9527

      注意,此处的[YOUR_DOWNLOAD_PATH]为你下载mitmproxy二进制文件解压后所对应的目录,就我而言的目录就是:~/Downloads/osx-mitmproxy-0.11.3 .  其中ip设置为iMac的ip,端口则按照你的个人喜好来。
      初始界面如下:

      mitmproxy初始运行界面
      mitmproxy初始运行界面

      输入“?”便可查看帮助界面(输入“q”回到正常界面):

      mitmproxy帮助界面
      mitmproxy帮助界面
    3. 在Android上设置代理。按照之前的步骤将Android所连接的wifi代理ip设置为:192.168.0.1,端口设置为:9527 。现在Android已经连上代理,iMac端便开始展示它所抓取到的包了(我在刷微博:)):
      mitmproxy抓包显示
      mitmproxy抓包显示

       

mitmproxy常见操作

mitmproxy的操作主要是通过命令行来解决的,很多操作和vi相同。一般说来,“q”代表返回。当mitmproxy回到抓包列表界面时,输入“q”就代表退出mitmproxy了。

清除抓包结果

当你处于抓包列表界面时,觉得太多的信息让你十分恼火,直接输入大写字母C便可以清楚所有的抓包结果。

查看抓包

在步骤3中我们可以看到一个黄色的指标,我们可以通过上下箭头(或者使用 “j”/”k”来上下选择)。直接回车便可以查看指标所选定的包的详细信息:

mitmproxy详细信息
mitmproxy抓包的Request详细信息

此时,我们可以使用tab键在“Request”和“Response”之间切换。这是“Response”的详细信息(这是一个张图片,所以下面乱码了):

mitmproxy抓去response信息
mitmproxy抓去response信息

当我们发现“Response”的信息比较乱的时候,我们可以选择合适的形式来展示,这个时候我们只要输入“m”便可以看到mitmproxy提供的不同展现形式,输入对应高亮的字母便可以看到相应的结果(输入“s”便可以以json形式展示):

mitmproxy 展示模式
mitmproxy 展示模式

mitmproxy修改抓包

如果这个时候我们需要编辑“Request”怎么办,很简单,输入字母“e”即可(注意图片最下方出现的提示(Edit request (query,path,url,header,form,raw body,method)?

mitmproxy编辑request
mitmproxy编辑request

我从mitmproxy给出的提示中选择了“method”,也就是编辑当前包的http方法,于是mitmproxy便给出了常见的方法:屏幕快照 2015-01-27 下午2.20.09在这些方法中,我要选择“trace”,便输入高亮的字母“t”即可,最后原来“Request”里面的方法就变成了TRACE了:

mitmproxy 修改request method
mitmproxy 修改request method

 

但是这个时候修改的request还没有生效,因为现在mitmproxy所展示的抓包信息只是记录了Android和server端之间的通信,因此我们现在编辑的抓包是已经传输过了,所以怎么办呢?很简单,重新request一下,输入字母“r”(代表“replay”)。这个时候我们就可以看到我们修改过的request得到的结果了:

mitmproxy 抓包replay效果
mitmproxy 抓包replay效果

此时我们输入“q”便可以回到之前的抓包列表了。这些都是历史抓包纪录,能不能实时地抓包呢?当然可以,这就是下面要说的拦截(Intercept)了。

mitmproxy拦截

何为拦截?之前开篇就介绍过mitmproxy是一个中间人代理工具,它位于客户端和Server 端之间,它可以获取客户端的Request然后修改,发送给Server 端;Server端得到Request之后在发出相应的Response又会被mitmproxy拦截,如果你想修改response,便可修改后再发给客户端。注意:这与之前修改抓包信息不同的是,前者的抓包已经发送给了服务器,而mitmproxy拦截则是获取了抓包,还未发送给服务器。也就是说如果我拦截了我手机上所有的request,那么我的手机将无法获取来自服务器的response。

那么我们如果进行拦截,怎么进行特定的拦截?输入字母“i”(代表Intercept filter)即可,此时界面便会让你输入想要拦截的条件:

mitmproxy 拦截
mitmproxy 拦截

mitmproxy的条件拦截在默认情况下是过滤抓包的URL的。也就是说当你直接输入要拦截的条件(比如输入“weibo”),那么接下来要出现抓包会将匹配的抓包整体变黄:

mitmproxy条件过滤效果
mitmproxy条件拦截效果

这些橘黄色的数据包都代表被拦截了,还未发送给服务器,这个时候你就可以对这些数据包进行修改,我们选择一个数据包enter进入:

mitmproxy 拦截 选择数据包
mitmproxy 拦截 选择数据包

与之前的类似,输入“e”,进行request编辑模式,然后输入“h”代表要编辑request的头部:

mitmproxy 编辑拦截包的头部
mitmproxy 编辑拦截包的头部

输入enter便可对高亮的User-Agent的值进行修改,上图的weibo版本之前是5.0的,被我改成了6.0 。我们还可以对header进行添加属性,输入“a”即可,然后使用tab分别键入key和value。这里我添加了“test-test”键值对:

mitmproxy 拦截header添加键值对
mitmproxy 拦截header添加键值对

至此,我对拦截的request header已经修改完毕,现在要做的就是我要认可接受这个修改,然后发给服务器。所以我们输入“a”(代表“accept”)即可,等到服务器响应后,注意,mitmproxy便又了拦截服务器发过来的response(注意那个“Response intercepted”):

mitmproxy 拦截response
mitmproxy 拦截response

现在如果你想修改这个response也可以,方式同上面修改request一样。这个时候我再输入“a”,代表我接受了这个response,然后这个response便可发给客户端了:

mitmproxy 拦截response之后accept
mitmproxy 拦截response之后accept

 

更多类型的mitmproxy拦截

同时mitmproxy还支持不同类型的条件过滤,之前在拦截字符串前面加上特定的参数比如我要拦截所有的POST request怎么办?输入:~m POST 即可(m代表method):

mitmproxy 拦截特定的request 方法
mitmproxy 拦截特定的request 方法

拦截所有的request: ~q

拦截特定的header: ~h

拦截特定的domain: ~d

拦截特定的响应代码(404之类的): ~c

其他还有很多类型,请参看mitmproxy官方文档

最后的几句话

在使用的过程中,虽然是命令行操作,但是mitmproxy都会在窗口的右下方给出醒目的提示,而且这些快捷键虽然多,但是都有对应的意思,只要我们理解一下,还是很好上手的。这些天接触了mitmproxy这个工具之后,发现用它来调试Android上的HTTP流量有点屈才了,它本身还提供了一个可供用户调用的库——libmproxy来定制自己的工具,它还提供了改进版的tcpdump——mitmdump。这个小玩意还真的挺不错的,也欢迎各位体验过后一起来交流交流。

如何调试 Android 上 HTTP(S) 流量

前面的话

在Android开发中我们常常会和API 打交道,可能你不想,但是这是避不开的。大部分情况下,调试发送网络请求和接收响应的过程都是十分痛苦的。

有多少次我们经过调试发现API的调用失败仅仅是因为我们的编码错了或者丢失了一个HTTP头部参数?在调试的过程中,我们发现出现错误的原因千奇百怪。总之我们要看到最终的请求是什么样子的不是一件容易的事情,响应也是如此

如果碰到困难,请使用代理

解决这样的问题有各种各样的方法和门道,但是我今天要分享的是在我看来最快,最容易也是最可行的方法。

由于调试HTTP请求和响应是相当繁琐的(调试HTTPS更加繁琐),因此在这种前提下你能使用的最好工具就是代理。当然,你肯定知道什么是代理,所以我就不啰嗦它的定义了。

现有的代理工具中它们的用法,特性以及操作系统的兼容性都各不相同,如何选择一款合适的代理呢?要我说,简单点,就用mitmproxy

mitmproxy

我已经无法用语言来形容mitmproxy的方便和强大了。用mitmproxy 官网上的介绍一句话,就是“an interactive, SSL-capable man-in-the-middle proxy for HTTP with a console interface”。没错,你可以通过控制台来操作它;没错,它还支持HTTPS;没错,它允许“对流量进行拦截,检测,修改和回放”;没错,它还是跨平台的,因为它是用Python写的。对了,我说了它是完全免费的这件事了吗?

使用它也是相当容易的。一旦你安装了它,便可通过在控制台输入以下命令启动它:

$ mitmproxy [-b IP_ADDR] [-p PORT]

代理已经在运行,你可以开始拦截网络流量了。接下来你就需要配置Android手机,将所有的流量都重定向到之前命令里设置的代理服务器地址上去(IP_ADDR + PORT)。

代理设置App: “Proxy Settings”

现在我们需要在Android手机上进行代理配置。具体步骤如下:

  1. 进入Android的Wi-Fi设置
  2. 长按当前连接的网络
  3. 选择“修改网络”选项
  4. 勾选“显示高级选项”
  5. 启用代理服务器并将代理设置为“手动”
  6. 输入之前设置好的的IP地址和端口。

如果要禁用代理同理。现在Android端的设置就大功告成了。

是不是觉得上面的步骤有点头疼?不急!幸亏还有Proxy Settings 这个App。用了Proxy Settings,上面繁琐的步骤就变得异常简单了。有了这个轻量级的App,你只需轻轻一点,便可轻松地开启或禁用网络连接里的代理设置。

Proxy Settings 的使用截图
Proxy Settings 的使用截图

通过Proxy Settings ,你可以创建多个代理配置。当你想要启用其中一个,只需点击当前连接的网络,启用代理,并选择你需要的配置。如果你要禁用代理,点击连接,并禁用它。

就这么简单,对了,它还不需要root权限哦?

那如何调试 HTTPS?

正如前面所提到的,mitmproxy还支持HTTPS拦截。这个特性让你在保持API endpoint 不变的情况下调试生产环境里的API变得异常方便。然而由于HTTPS的工作方式,我们需要安装一个自定义的SSL证书,让mitmproxy对所拦截的流量进行解密。

听起来HTTPS拦截的步骤好像有点麻烦,其实很简单。你只需按照mitmproxy官网的这篇设置指南便可轻易地完成设置。记得在启动mitmproxy的时候需要额外添加一个参数,如下命令所示:

$ mitmproxy -a IP_ADDR -p PORT —-no-upstream-cert

不过此处还有个小问题。Android是以一种加密的形式来保存SSL证书的,而这种加密的形式即用户设置的手机解锁信息。也就是说,你在Android上安装任何SSL证书之前,系统都会提示你设置解锁手机的方式,比如输入PIN码,密码或者是某种图案。

调试3G/4G

3G/4G这种情况下设置代理更难了。系统设置中没有为3G/4G连接提供代理设置接口。但是!你可以通过你的手机“移动热点”功能来实现在3G/4G这种情况下设置代理。你要准备的就是:

  1. 一台可以连接3G/4G网络的Android手机
  2. 一台开启了“开发者模式”的手机(另一台了)
  3. 你的笔记本电脑

接下来的步骤就简单啦:

  1. 在第一台手机上激活“移动热点”功能
  2. 将你的笔记本电脑和第二台手机(“开启了开发者模式”)连上移动热点
  3. 在笔记本电脑上启动 mitmproxy,并将IP地址设为hotspot所对应的(通常是192.168.43.xxx 之类的)
  4. 在第二台手机上使用Proxy Settings设置代理

OK,在3G/4G这种情况下设置代理就是这样子的。

 

总结

到目前为止,我还试过其他两种代理工具,CharlesFiddler。 但是mitmproxy完爆他们两个。Charles 可能是在功能,灵活性以及操作系统支持这几个方面和mitmproxy最接近的,但是它一不免费,二不开源。 对于 Fiddler, 它只能在Windows平台上使用。

mitmproxy + Proxy Settings 的结合让我省了不少心,我希望它们也能为你所用。

如果你有更好的解决方法,记得告诉我。☺

本文翻译自音乐App musiXmatch 公司高级Android工程Sebastiano Gottardo。原文地址:https://medium.com/@rotxed/how-to-debug-http-s-traffic-on-android-7fbe5d2a34

UPDATE:有同学反应对这个工具到底怎么使用不是很清楚,于是我打算在本文基础上再增加一些实践相关的文字,后来发现篇幅过于臃肿,干脆新写了一篇关于mitmproxy实践的文章,希望能给大家一些启发。