在Safari,IE和iOS设备上使用Fiddler信任证书并捕获流量

时间:2018-02-14 16:56:49

标签: c# ios ssl fiddler fiddlercore

我在gist here中设置了我的Fiddler代理。

代码:

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);
            }
        }
    }

其目的是捕获和分析来自Windows,Mac OS X,Android和iOS浏览器(主要是桌面和移动设备上的Chrome,Firefox和Safari)的流量。

到目前为止,似乎正在努力:

  • Windows浏览器:Chrome,Firefox。不适用于IE和Edge
  • Android:Chrome
  • Mac OS:Chrome,Firefox。 Safari无法正常工作
  • iOS:无

在我的日志文件中,我发现Fiddler在浏览器无效的情况下记录了以下错误(适用于所有设备)。 HTTPS请求的示例:

  

2018-02-14 17:25:50.3860 |信息| ** LogString:   !SecureClientPipeDirect失败:System.IO.IOException身份验证   失败,因为远程方已关闭传输流。对于   pipe(CN = *。optimizely.com,O = DO_NOT_TRUST_BC,OU =创建者   http://www.fiddler2.com

从我在过去几天阅读的内容中试图找到解决方案的原因,原因是设备上不信任的证书。

使用他们提供的名为BrowserStack Local的功能在BrowserStack上运行测试。有关它的详细信息是herehere

现在我的问题可以在桌面和移动之间分开:

  • 为什么Chrome和Firefox能够在IE,Edge和Safari无法提出HTTPS请求的情况下执行此操作?
  • 对于iOS,特别是有一个针对iOS文档的Fiddler here,用于指定配置设备所需的步骤。但是,正如我已经提到的,我没有使用内部iOS设备,而是使用BrowserStack提供的物理设备。有没有办法以编程方式信任iOS设备上的证书(iOS 9.x,iOS 10.x,iOS 11.x)?

我可以使用任何变通办法吗?

修改 FiddlerCore and BrowserStack Local logs are here.

1 个答案:

答案 0 :(得分:4)

从第二个问题开始,官方Telerik论坛上有关于IOS设备的讨论说明:

  

不应启用SSL2,除非Fiddler中未启用SSL2   你开始用脚射击自己。

     

如果您已正确配置iOS设备以信任Fiddler的root   证书,然后HTTPS拦截将在客户端正常工作   除非正在使用证书固定。证书固定时   在Chrome中无关紧要,在iOS上他们忽略了Trusted   证书存储,因此Fiddler拦截不会   工作。但大多数网站和应用程序都不使用固定。如果是网站或应用   使用钉扎,没有解决方法没有越狱设备。   这不是Fiddler特有的限制 - 每次HTTPS解密   代理有完全相同的限制。

我想这将回答你的第一个答案以及IE正在使用证书固定以及我记得的内容。