views:

88

answers:

1

Since HTTPS proxies will replace the SSL certificate with their own, what are my options to determine if a given HTTPS connection has a proxy in the middle?

I will use this information to determine my application policy, since there are cases where I want a 100% end-to-end encrypted tunnel with no decryption by any 3rd party.

Even better if you can tell me how to determine this via C# in a .NET application or Silverlight.

For starters, here is a sample method to validate a certificate using .NET, but I'm still not sure how to use this to determine what part of the cert to validate. In addition, I think the ServicePointManger is more of a "global" connection class. Using this may be too broad when I'm testing a single HTTP connection, and I'm not sure if ServicePointManager is available within Silverlight.

http://msdn.microsoft.com/en-us/library/bb408523.aspx

+1  A: 

You have a couple of options. The first option is to use the ServicePointManager class. You are correct in that it manages all service points, but you can use the "sender" parameter in the callback method to differentiate between the different service points:

void SomeMethod()
{
    ServicePointManager.ServerCertificateValidationCallback += 
        ValidateServerCertificate;

    var url = "https://mail.google.com/mail/?shva=1#inbox";
    var request = (HttpWebRequest)WebRequest.Create(url);
    request.GetResponse();
}

private static bool ValidateServerCertificate(object sender, 
        X509Certificate certificate, X509Chain chain, 
        SslPolicyErrors sslpolicyerrors)
{
    if(sender is HttpWebRequest)
    {
        var request = (HttpWebRequest) sender;
        if(request.RequestUri.ToString() == "https://mail.google.com/mail/?shva=1#inbox")
        {
            return (certificate.GetPublicKeyString() == "The public key string you expect");
        }
    }
    return true;
}

This option will work for manually-created HttpWebRequest and WCF-created requests, as the "sender" will be HttpWebRequest for both. I'm not sure if the "sender" will be anything other than an HttpWebRequest.

The second option is to get the certificate from the service point directly:

void SomeMethod()
{
    ServicePointManager.ServerCertificateValidationCallback += 
        ValidateServerCertificate;

    var url = "https://mail.google.com/mail/?shva=1#inbox";
    var request = (HttpWebRequest)WebRequest.Create(url);
    request.GetResponse();

    var serverCert = request.ServicePoint.Certificate;
    // Validate the certificate.
}

I couldn't figure out if it's possible to get the ServicePoint used by a WCF proxy. If it's not possible, this option won't work for WCF. Other than that, the biggest difference is that the first option prevents the connection if the certificate validation fails, while the second method won't validate until after the connection has been made.

If you just need to determine if a request is going to pass through a proxy:

var httpRequest = (HttpWebRequest)WebRequest.Create("someurl");
var isUsingProxy = DoesRequstUseProxy(request);

bool DoesRequestUseProxy(HttpWebRequest request)
{
    if(request.Proxy == null)
    {
        return false;
    }

    return request.Proxy.GetProxy(request.RequestUri) != request.RequestUri;
}
Andy Wilson
Thank you, but I still need to figure out what to do with the cert when I get it. Is there no generic way to detect a proxy via a cert? Must I hard code the expected public key string into my app?Also I'm not sure if this approach works in Silverlight... I doubt if I can get ServicePointManager access within the SLI Sandbox
MakerOfThings7
The approach of DoesRequestUseProxy will not work if "WCCP" is used at the firewall. WCCP is a transparent proxy that does not require client configuration. BlueCoat is an example of a product that will interact with all data coming from a firewall and transparently proxy HTTPS traffic. It is this reason that I think the only universal method is to analyze the cert itself.
MakerOfThings7
I updated my answer to show how to detect if a web request is using a proxy. Unfortunately, I just confirmed that none of the code in my answer will work in Silverlight.
Andy Wilson
Thanks for checking into the Silverlight approach :)
MakerOfThings7