{"id":651,"date":"2018-10-21T02:59:59","date_gmt":"2018-10-20T18:59:59","guid":{"rendered":"https:\/\/vinta.ws\/code\/?p=651"},"modified":"2026-03-17T01:21:04","modified_gmt":"2026-03-16T17:21:04","slug":"mitmproxy-proxy-any-application-network-traffic-through-your-local-machine","status":"publish","type":"post","link":"https:\/\/vinta.ws\/code\/mitmproxy-proxy-any-application-network-traffic-through-your-local-machine.html","title":{"rendered":"mitmproxy: proxy any network traffic through your local machine"},"content":{"rendered":"<p>mitmproxy is your swiss-army knife for interactive HTTP\/HTTPS proxy. In fact, it can be used to intercept, inspect, modify and replay web traffic such as HTTP\/1, HTTP\/2, WebSockets, or any other SSL\/TLS-protected protocols.<\/p>\n<p>Moreover, mitmproxy has a powerful Python API that offers full control over any intercepted request and response.<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/mitmproxy.org\/\">https:\/\/mitmproxy.org\/<\/a><br \/>\n<a href=\"https:\/\/docs.mitmproxy.org\/stable\/\">https:\/\/docs.mitmproxy.org\/stable\/<\/a><\/p>\n<h2>Concept<\/h2>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mitmproxy.org\/stable\/concepts-howmitmproxyworks\/\">https:\/\/docs.mitmproxy.org\/stable\/concepts-howmitmproxyworks\/<\/a><\/p>\n<h2>Installation<\/h2>\n<pre class=\"line-numbers\"><code class=\"language-console\">$ brew install mitmproxy\n\n$ mitmproxy --version\nMitmproxy: 4.0.4\nPython:    3.7.0\nOpenSSL:   OpenSSL 1.0.2p  14 Aug 2018\nPlatform:  Darwin-18.0.0-x86_64-i386-64bit<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mitmproxy.org\/stable\/overview-installation\/\">https:\/\/docs.mitmproxy.org\/stable\/overview-installation\/<\/a><\/p>\n<h2>Configuration<\/h2>\n<p>Make your computer become the man in a man-in-the-middle attack.<\/p>\n<h3>macOS<\/h3>\n<pre class=\"line-numbers\"><code class=\"language-bash\">$ ipconfig getifaddr en0\n192.168.0.128\n\n$ mitmproxy -p 8888\n# or\n$ mitmweb -p 8888\n$ open http:\/\/127.0.0.1:8081\/<\/code><\/pre>\n<p>Flow List keys:<\/p>\n<ul>\n<li><code>?<\/code>: Show help<\/li>\n<li><code>q<\/code>: Exit the current view<\/li>\n<li><code>f<\/code>: Set view filter<\/li>\n<li><code>r<\/code>: Replay this flow<\/li>\n<li><code>i<\/code>: Set intercept filter<\/li>\n<li><code>hjkl<\/code> or <code>arrow<\/code>: Move left\/down\/up\/right<\/li>\n<li><code>enter<\/code>: Select<\/li>\n<\/ul>\n<p>Flow Details keys:<\/p>\n<ul>\n<li><code>tab<\/code>: Select next<\/li>\n<li><code>m<\/code>: Set flow view mode<\/li>\n<li><code>e<\/code>: Edit this flow (request or response)<\/li>\n<li><code>a<\/code>: Accept this intercepted flow<\/li>\n<\/ul>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mitmproxy.org\/stable\/tools-mitmproxy\/\">https:\/\/docs.mitmproxy.org\/stable\/tools-mitmproxy\/<\/a><br \/>\n<a href=\"https:\/\/github.com\/mitmproxy\/mitmproxy\/blob\/master\/mitmproxy\/tools\/console\/defaultkeys.py\">https:\/\/github.com\/mitmproxy\/mitmproxy\/blob\/master\/mitmproxy\/tools\/console\/defaultkeys.py<\/a><\/p>\n<h3>iOS<\/h3>\n<ul>\n<li>Go to Settings &gt; Wi-Fi &gt; Your Wi-Fi &gt; Configure Proxy\n<ul>\n<li>Select Manual, enter the following values:\n<ul>\n<li>Server: <code>192.168.0.128<\/code><\/li>\n<li>Port: <code>8888<\/code><\/li>\n<li>Authentication: unchecked<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Open <a href=\"http:\/\/mitm.it\/\">http:\/\/mitm.it\/<\/a> on Safari\n<ul>\n<li>Install the corresponding certificate for your device<\/li>\n<\/ul>\n<\/li>\n<li>Go to Settings &gt; General &gt; About &gt; Certificate Trust Settings\n<ul>\n<li>Turn on the <code>mitmproxy<\/code> certificate<\/li>\n<\/ul>\n<\/li>\n<li>Open any app you want to watch<\/li>\n<\/ul>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mitmproxy.org\/stable\/concepts-certificates\/\">https:\/\/docs.mitmproxy.org\/stable\/concepts-certificates\/<\/a><\/p>\n<h2>Usage<\/h2>\n<p>The most exciting feature is you could alter any request and response using a Python script, <code>mitmdump -s<\/code>!<\/p>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mitmproxy.org\/stable\/tools-mitmdump\/\">https:\/\/docs.mitmproxy.org\/stable\/tools-mitmdump\/<\/a><br \/>\n<a href=\"https:\/\/github.com\/mitmproxy\/mitmproxy\/tree\/master\/examples\">https:\/\/github.com\/mitmproxy\/mitmproxy\/tree\/master\/examples<\/a><\/p>\n<h3>Deal With Certificate Pinning<\/h3>\n<p>You can use your own certificate by passing the <code>--certs example.com=\/path\/to\/example.com.pem<\/code> option to mitmproxy. Mitmproxy then uses the provided certificate for interception of the specified domain.<\/p>\n<p>The certificate file is expected to be in the PEM format which would roughly look like this:<\/p>\n<pre class=\"line-numbers\"><code class=\"language-txt\">-----BEGIN PRIVATE KEY-----\n&lt;private key&gt;\n-----END PRIVATE KEY-----\n\n-----BEGIN CERTIFICATE-----\n&lt;cert&gt;\n-----END CERTIFICATE-----\n\n-----BEGIN CERTIFICATE-----\n&lt;intermediary cert (optional)&gt;\n-----END CERTIFICATE-----<\/code><\/pre>\n<pre class=\"line-numbers\"><code class=\"language-bash\">$ mitmproxy -p 8888 --certs example.com=example.com.pem<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/docs.mitmproxy.org\/stable\/concepts-certificates\/#using-a-custom-server-certificate\">https:\/\/docs.mitmproxy.org\/stable\/concepts-certificates\/#using-a-custom-server-certificate<\/a><\/p>\n<h3>Redirect Requests To Your Local Development Server<\/h3>\n<pre class=\"line-numbers\"><code class=\"language-python\"># redirect_to_localhost.py\nfrom mitmproxy import ctx\nfrom mitmproxy import http\n\nREMOTE_HOST = 'api.example.com'\nDEV_HOST = '192.168.0.128'\nDEV_PORT = 8000\n\ndef request(flow: http.HTTPFlow) -&gt; None:\n    if flow.request.pretty_host in [REMOTE_HOST, DEV_HOST]:\n        ctx.log.info('=== request')\n        ctx.log.info(str(flow.request.headers))\n        ctx.log.info(f'content: {str(flow.request.content)}')\n\n        flow.request.scheme = 'http'\n        flow.request.host = DEV_HOST\n        flow.request.port = DEV_PORT\n\ndef response(flow: http.HTTPFlow) -&gt; None:\n    if flow.request.pretty_host == DEV_HOST:\n        ctx.log.info('=== response')\n        ctx.log.info(str(flow.response.headers))\n        if flow.response.headers.get('Content-Type', '').startswith('image\/'):\n            return\n        ctx.log.info(f'body: {str(flow.response.get_content())}')<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/discourse.mitmproxy.org\/t\/reverse-mode-change-request-host-according-to-the-sni-https\/466\">https:\/\/discourse.mitmproxy.org\/t\/reverse-mode-change-request-host-according-to-the-sni-https\/466<\/a><\/p>\n<p>You could use <strong>negative regex<\/strong> with <code>--ignore-hosts<\/code> to only watch specific domains. Of course, you are still able to blacklist any domain you don't want: <code>--ignore-hosts &#039;apple.com|icloud.com|itunes.com|facebook.com|googleapis.com|crashlytics.com&#039;<\/code>.<\/p>\n<p>Currently, changing the <code>Host<\/code> server for HTTP\/2 connections is not allowed, but you could just disable HTTP\/2 proxy to solve the issue if you don't need HTTP\/2 for local development.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-bash\">$ mitmdump -p 8888 \n--certs example.com=example.com.pem \n-v --flow-detail 3 \n--ignore-hosts '^(?!.*example.com)' \n--no-http2 \n-s redirect_to_localhost.py<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/stackoverflow.com\/questions\/29414158\/regex-negative-lookahead-with-wildcard\">https:\/\/stackoverflow.com\/questions\/29414158\/regex-negative-lookahead-with-wildcard<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>mitmproxy is a free and open source interactive HTTPS proxy.<\/p>\n","protected":false},"author":1,"featured_media":652,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[38,4,116],"tags":[101,29,2],"class_list":["post-651","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-about-devops","category-about-python","category-about-web-development","tag-cli-tool","tag-debug","tag-python"],"_links":{"self":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts\/651","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/comments?post=651"}],"version-history":[{"count":0,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts\/651\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/media\/652"}],"wp:attachment":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/media?parent=651"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/categories?post=651"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/tags?post=651"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}