Einfache und barrierefreie Netzwerkverkehranalyse

Geschrieben von Eric Scheibler am 12.06.2021

Während der Entwicklung einer Android App musste ich unlängst die abgesendeten Netzwerkanfragen analysieren. Unter Android selbst kam ich nicht weiter. Die Analyse gestaltete sich aber unter Zuhilfenahme von mitmproxy erstaunlich einfach.

Im folgenden Artikel beschreibe ich dessen Installation und die Verwendung in Android Apps und wget.

Grundsätzlich funktioniert das wie ein mitm Angriff. Man installiert einen Proxyserver innerhalb des lokalen Netzwerks und konfiguriert die Clients, sodass sie ihre Anfragen über den Proxy verschicken. Ich habe mich für mitmproxy entschieden, da es für die Linux Konsole verfügbar, einfach zu benutzen und mit Screenreadern wie brltty recht gut bedienbar ist.

Installation: sudo apt install mitmproxy

Start: mitmproxy --listen-host 192.168.100.100 --listen-port 22222 --save-stream-file +requests.log

Wget

Zunächst testweise eine http Anfrage:

wget -e https_proxy=192.168.100.100:22222 http://example.org

Diese sollte in der mitmproxy Hauptansicht auftauchen.

Wer auch verschlüsselte Anfragen analysieren möchte, muss in seinem Client das SSL Zertifikat angeben, welches mitmproxy beim ersten Start generiert hat. Man findet es unter ~/.mitmproxy/mitmproxy-ca-cert.pem. Die Datei muss auf den Clientrechner kopiert und wie folgt verwendet werden:

wget -e https_proxy=192.168.100.100:22222 --ca-certificate /path/to/mitmproxy-ca-cert.pem https://example.org

Wenn alles geklappt hat, enthält die mitmproxy Hauptansicht nun zwei Einträge. Mit den Pfeiltasten bewegt man sich durch die Liste, mit ENTER öffnet man die Details.

Leider unterstützt die UI den Hardware Konsolencursor nicht. D.h. Screenreader lesen den ausgewählten Listeneintrag beim navigieren nicht korrekt vor. Wer brltty einsetzt, kann allerdings die autom. Cursorverfolgung vorübergehend deaktivieren (CAPSLOCK+ENTER) und dem ausgewählten Eintrag manuell folgen. Selbigen erkennt man an einem vorangestellten “>>”.

Die Detailansicht besteht aus drei Tabs: Request, Response und Details. Man wechselt entweder mit den Pfeiltasten links und rechts oder via TAB durch die Reiter. Mich interessierten vor allem die Cookie Header der Anfrage - daher wurde ich bereits im Requests-Tab fündig.

Android app development

Zunächst muss das SSL Zertifikat von oben zu den Resourcen der App hinzugefügt werden:

mkdir /path/to/android_project/app/src/main/res/raw/
cp ~/.mitmproxy/mitmproxy-ca-cert.pem /path/to/android_project/app/src/main/res/raw/mitm_proxy.pem

Anschließend den folgenden Programmcode verwenden, um

  1. den Proxy zu konfigurieren und
  2. das SSL Zertifikat für die Anfrage zu setzen.
import org.example.project.BuildConfig;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

URL url = new URL("https://example.org");
String proxyHost = "192.168.100.100";
int proxyPort = 22222;

HttpsURLConnection connection = null;
if (BuildConfig.DEBUG) {

    Proxy proxy = new Proxy(
            Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
    connection = (HttpsURLConnection) url.openConnection(proxy);

    try {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream caInput;
        // Create a KeyStore containing our trusted CAs
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, null);
        // load mitm_proxy certificate
        caInput = ApplicationInstance.getContext().getResources().openRawResource(R.raw.mitm_proxy);
        try {
            keyStore.setCertificateEntry("ca1", cf.generateCertificate(caInput));
        } finally {
            caInput.close();
        }
        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);
        // Create an SSLContext that uses our TrustManager
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);
        connection.setSSLSocketFactory(sslContext.getSocketFactory());
    } catch (Exception e) {
        System.out.println(
                String.format("Cert exception: %1$s", e.getMessage()));
    }

} else {
    connection = (HttpsURLConnection) url.openConnection();
}

Alternativ kann man den Proxy auch systemweit setzen. Dann muss man das Zertifikat in den Android Einstellungen, Abschnitt Sicherheit hinzufügen. Leider berücksichtigen nicht alle Apps die systemweite Proxyeinstellung - z.B. Browser bringen gern ihre eigene Konfiguration mit.

Wer nur die Anfragen seiner eigenen App analysieren möchte, sollte daher den oben beschriebenen, direkten Weg einschlagen - das ist zumindest meiner Erfahrung nach deutlich unkomplizierter.