简体   繁体   中英

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

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM