Trust certs and capture traffic using Fiddler on Safari, IE and iOS devices
Asked Answered
D

1

7

I have set-up my Fiddler Proxy like in the gist here.

Code:

public class ProxyConfig
    {
        private readonly string _secureEndpointHostname = IPAddress.Any.ToString();
        private readonly int _secureEndpointPort = 4555;
        private readonly int _port = 18882;

        private static readonly ICollection<Session> AllSessions = new List<Session>();

        private static Fiddler.Proxy _secureEndpoint;

        private static readonly LoggerCnx Logger = new LoggerCnx();
        private Action<string> onRequest;

        public ProxyConfig()
        {
        }

        public ProxyConfig(Action<string> onRequest)
        {
            this.onRequest = onRequest;
        }

        public void SetupProxyListener()
        {
            FiddlerApplication.SetAppDisplayName("FiddlerCoreProxyApp");

            // This is a workaround for known issue in .NET Core - https://github.com/dotnet/coreclr/issues/12668
            CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");

            // Simply echo notifications to the console.  Because Fiddler.CONFIG.QuietMode=true 
            // by default, we must handle notifying the user ourselves.
            //Fiddler.FiddlerApplication.OnNotification += delegate (object sender, NotificationEventArgs oNEA) { System.Diagnostics.Debug.WriteLine("** NotifyUser: " + oNEA.NotifyString); };
            FiddlerApplication.Log.OnLogString += delegate (object sender, LogEventArgs oLEA) { Logger.Info("** LogString: " + oLEA.LogString); };

            FiddlerApplication.BeforeRequest += delegate (Session session)
            {

                if (!CertMaker.rootCertIsTrusted())
                {
                    CertMaker.trustRootCert();
                }

                if (onRequest != null)
                {
                    onRequest(session.fullUrl);
                }

                // In order to enable response tampering, buffering mode MUST
                // be enabled; this allows FiddlerCore to permit modification of
                // the response in the BeforeResponse handler rather than streaming
                // the response to the client as the response comes in.
                session.bBufferResponse = false;
                lock (AllSessions)
                {
                    AllSessions.Add(session);
                    Logger.Info("Session: " + session.fullUrl);
                }
                session["X-AutoAuth"] = "(default)";

                if ((session.oRequest.pipeClient.LocalPort == _secureEndpointPort) && (session.hostname == _secureEndpointHostname))
                {
                    session.utilCreateResponseAndBypassServer();
                    session.oResponse.headers.SetStatus(200, "OK");
                    session.oResponse["Content-Type"] = "text/html; charset=UTF-8";
                    session.oResponse["Cache-Control"] = "private, max-age=0";
                    session.utilSetResponseBody("<html><body>Request for httpS://" + _secureEndpointHostname + ":" + _secureEndpointPort.ToString() + " received. Your request was:<br /><plaintext>" + session.oRequest.headers.ToString());
                }
            };

            Logger.Info($"Starting {FiddlerApplication.GetVersionString()}...");
            CONFIG.IgnoreServerCertErrors = true;
            CONFIG.bCaptureCONNECT = true;

            FiddlerApplication.Prefs.SetBoolPref("fiddler.network.streaming.abortifclientaborts", true);

            FiddlerCoreStartupFlags startupFlags = FiddlerCoreStartupFlags.Default;

            startupFlags = (startupFlags | FiddlerCoreStartupFlags.DecryptSSL);
            startupFlags = (startupFlags | FiddlerCoreStartupFlags.AllowRemoteClients);
            startupFlags = (startupFlags & ~FiddlerCoreStartupFlags.MonitorAllConnections);
            startupFlags = (startupFlags & ~FiddlerCoreStartupFlags.CaptureLocalhostTraffic);

            FiddlerApplication.Startup(_port, startupFlags);

            Logger.Info("Created endpoint listening on port {0}", _port);

            Logger.Info("Starting with settings: [{0}]", startupFlags);
            Logger.Info("Gateway: {0}", CONFIG.UpstreamGateway.ToString());

            // Create a HTTPS listener, useful for when FiddlerCore is masquerading as a HTTPS server
            // instead of acting as a normal CERN-style proxy server.
            _secureEndpoint = FiddlerApplication.CreateProxyEndpoint(_secureEndpointPort, true, _secureEndpointHostname);
            if (null != _secureEndpoint)
            {
                Logger.Info("Created secure endpoint listening on port {0}, using a HTTPS certificate for '{1}'", _secureEndpointPort, _secureEndpointHostname);
            }
        }
    }

Its purpose is to capture and analyze traffic from Windows, Mac OS X, Android and iOS browsers (Chrome, Firefox and Safari mostly, on both Desktop and Mobile devices).

So far, it seems to be working on:

  • Windows browsers: Chrome, Firefox. Not working on IE and Edge
  • Android: Chrome
  • Mac OS: Chrome, Firefox. Safari is not working
  • iOS: none

In my logs files I'm seeing the following errors logged by Fiddler on browsers not working (for all devices). Example for an HTTPS request:

2018-02-14 17:25:50.3860 | INFO | ** LogString: !SecureClientPipeDirect failed: System.IO.IOException Authentication failed because the remote party has closed the transport stream. for pipe (CN=*.optimizely.com, O=DO_NOT_TRUST_BC, OU=Created by http://www.fiddler2.com)

From what I read in the last couple of day trying to figure out a solution for this, the reason would be the certificates that are not trusted on the device.

The tests are being ran on BrowserStack using the feature they provide called BrowserStack Local. Details about it are here and here.

Now my questions could be split between Desktop and Mobile:

  • Why is Chrome and Firefox able to make HTTPS requests while IE, Edge and Safari fails to do so?
  • For iOS specifically, there's a Fiddler for iOS documentation here specifying the steps required in order to configure the device. However, as I already mentioned, I'm not using in-house iOS devices, but physical ones provided by BrowserStack. Is there a way to programatically trust a certificate on an iOS device (iOS 9.x, iOS 10.x, iOS 11.x)?

Are there any workarounds that I could use?

EDIT: FiddlerCore and BrowserStack Local logs are here.

Dori answered 14/2, 2018 at 16:56 Comment(10)
I fail to see how this question is related to c# or programming in general.Sweetening
Fiddler is a .NET/C# based proxy tool and I'm looking for flaws/errors/enhancements in the gist provided that will help me solve the issue. I don't see why it's not C# or programming related.Dori
Can you try following? ServicePointManager .ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;Gussie
Did you try to add [User-Agent]? msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspxBeni
@FaizanRabbani I've added the cert validation callback but didn't saw any changes.Dori
@Beni Tried adding the User-Agent but still didn't work (added the one for iOS): session.oRequest["User-Agent"] = "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0_1 like Mac OS X) AppleWebKit/604.2.10 (KHTML, like Gecko) Version/11.0 Mobile/15A8391 Safari/604.1"; session.oRequest["Connection"] = "keep-alive";Dori
I would use a sniffer like wireshark or fiddler and compare the good results with bad results. Usually it is just a header that needs to be added. Check the http messages and compare the headers. Check and see if you are getting http 1.0 (stream mode) or http1.1 (chunk mode) for both request and response.Beni
Adjusting |ServicePointManager .ServerCertificateValidationCallback| is only useful to put inside a client application that you want to (dangerously) ignore the validity of a server's certificate. It's not useful in FiddlerCore.Substantiate
@Cosmin, See if this helps telerik.com/forums/…Sporocyst
@Substantiate As a note, all steps from here were already executed (prior to this SO post), but still no success.Dori
H
4

Starting from your second question, there is a discussion regarding IOS devices here on the official Telerik forums stating:

SSL2 shouldn't ever be enabled, and it isn't enabled in Fiddler unless you go out of the way to shoot yourself in the foot.

If you've properly configured your iOS device to trust Fiddler's root certificate, then HTTPS interception will work properly in clients except where certificate pinning is in use. While Certificate Pinning in Chrome won't matter on the Desktop, on iOS they ignore the Trusted Certificates store and as a consequence Fiddler interception will not work. But most sites and apps do not use pinning. If a site or app uses pinning, there's no workaround short of jailbreaking the device. This isn't a limitation unique to Fiddler-- every HTTPS-decrypting proxy has exactly the same limitation.

I guess that will answer your first answer as well as IE is using certificate pinning as well as much as I recall.

Huskey answered 21/2, 2018 at 10:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.