Howto: Ignoring web browser certificate errors in a webbrowser host

The webbrowser queries host services via IServiceProvider implemented on the ActiveX host. One of the services is IHttpSecurity, which can be used to override the certificate problem dialog.

Security warning: ignoring security problems can compromise your application.

IHttpSecurity is derived from IWindowForBindingUI, so the host needs to implement it too.

In Windows forms, customizing certificate error handling involves the following:

  • derive a class from WebBrowser
  • create a nested class derived from WebBrowser.WebBrowserSite (the only way you can derive from the nested class)
  • overwrite CreateWebBrowserSiteBase and return a new instance of your webbrowser site.
  • implement IServiceProvider on the webbrowser site
  • implement IServiceProvider.QueryService so it returns an IHttpSecurity imepleemntation when the IHttpSecurity service is requested
  • handle IHttpSecurity.OnSecurityProblem and return S_OK (warning: undocumented code, won’t work in IE6)
  • use the new webbrowser in the form

Sample code:

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void webBrowser1_DocumentCompleted(object sender,
            WebBrowserDocumentCompletedEventArgs e)
        {
            if (e.Url.ToString() == “about:blank”)
            {
                //create a certificate mismatch
                webBrowser1.Navigate(“https://74.125.225.229”);
            }
        }
    }
    [Guid(“6D5140C1-7436-11CE-8034-00AA006009FA”)]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComImport]
    public interface UCOMIServiceProvider
    {
        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int QueryService(
            [In] ref Guid guidService,
            [In] ref Guid riid,
            [Out] out IntPtr ppvObject);
    }
    [ComImport()]
    [ComVisible(true)]
    [Guid(“79eac9d5-bafa-11ce-8c82-00aa004ba90b”)]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IWindowForBindingUI
    {
        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int GetWindow(
            [In] ref Guid rguidReason,
            [In, Out] ref IntPtr phwnd);
    }
    [ComImport()]
    [ComVisible(true)]
    [Guid(“79eac9d7-bafa-11ce-8c82-00aa004ba90b”)]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IHttpSecurity
    {
        //derived from IWindowForBindingUI
        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int GetWindow(
            [In] ref Guid rguidReason,
            [In, Out] ref IntPtr phwnd);
        [PreserveSig]
        int OnSecurityProblem(
            [In, MarshalAs(UnmanagedType.U4)] uint dwProblem);
    }
    public class MyWebBrowser : WebBrowser
    {
        public static Guid IID_IHttpSecurity
            = new Guid(“79eac9d7-bafa-11ce-8c82-00aa004ba90b”);
        public static Guid IID_IWindowForBindingUI
            = new Guid(“79eac9d5-bafa-11ce-8c82-00aa004ba90b”);
        public const int S_OK = 0;
        public const int S_FALSE = 1;
        public const int E_NOINTERFACE = unchecked((int)0x80004002);
        public const int RPC_E_RETRY = unchecked((int)0x80010109);
        protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
        {
            return new MyWebBrowserSite(this);
        }
        class MyWebBrowserSite : WebBrowserSite,
            UCOMIServiceProvider,
            IHttpSecurity,
            IWindowForBindingUI
        {
            private MyWebBrowser myWebBrowser;
            public MyWebBrowserSite(MyWebBrowser myWebBrowser)
                :base(myWebBrowser)
            {
                this.myWebBrowser = myWebBrowser;
            }
            public int QueryService(ref Guid guidService
                , ref Guid riid
                , out IntPtr ppvObject)
            {
                if (riid ==IID_IHttpSecurity)
                {
                    ppvObject= Marshal.GetComInterfaceForObject(this
                        , typeof(IHttpSecurity));
                    return S_OK;
                }
                if (riid == IID_IWindowForBindingUI)
                {
                    ppvObject = Marshal.GetComInterfaceForObject(this
                        , typeof(IWindowForBindingUI));
                    return S_OK;
                }
                ppvObject = IntPtr.Zero;
                return E_NOINTERFACE;
            }
            public int GetWindow(ref Guid rguidReason
                , ref IntPtr phwnd)
            {
                if (rguidReason == IID_IHttpSecurity
                    || rguidReason == IID_IWindowForBindingUI)
                {
                    phwnd = myWebBrowser.Handle;
                    return S_OK;
                }
                else
                {
                    phwnd = IntPtr.Zero;
                    return S_FALSE;
                }
            }
            public int OnSecurityProblem(uint dwProblem)
            {
                //ignore errors
                //undocumented return code, does not work on IE6
                return S_OK;
            }
        }
    }
For sample code in providing the service using MFC, check Handle NewWindow3 and ShowModalDialog in CHtmlView. The way to implements IHttpSecurity is similar to how the article exposes the INewWindowManager service to the webbrowser control.

20 responses to “Howto: Ignoring web browser certificate errors in a webbrowser host”

  1. Thank you for the post blog. This was what I have been looking for.

    I have one question. I want to ignore only when specific URL.
    Is there a way to know where the error made in the URL?

    public const int ERROR_INTERNET_SEC_CERT_CN_INVALID = 12038;
    public int OnSecurityProblem(uint dwProblem)
    {
    if (dwProblem == ERROR_INTERNET_SEC_CERT_CN_INVALID
    /* && url == ‘https://my-webpage/’ */) { // TODO
    return S_TRUE;
    }
    return S_FALSE;
    }

    Thanks!

    1. I think you need to dig into Asynchronous Pluggable Protocols.

  2. hi
    do you have download example? I really dont understand some things, like how to generate that GUI numbers, what “using” librarys include. This is what I am looking for, but I can’t make it compile

    1. The GUID numbers are already in the code. What error do you have?

  3. Hi,
    I have a webbrowser host written in c++. I have implemented IServiceProvider and IHTTPSecurity on the host. However it seems that IServiceProvider is not called. Can you help me?

    class ATL_NO_VTABLE CWBContainer :
    public CComObjectRootEx,
    public CComCoClass,
    public IDispatchImpl,
    public IOleClientSite,
    public IOleInPlaceSite,
    public IDocHostUIHandler,
    public IDocHostShowUI,
    public IOleCommandTarget,
    public IDispEventImpl,
    public CWindowImpl,
    public IServiceProviderImpl,
    public IHttpSecurity
    {

    BEGIN_SERVICE_MAP(CWBContainer)
    SERVICE_ENTRY(IID_IHttpSecurity)
    END_SERVICE_MAP()

    }

    1. are IDocHostUIHandler methods getting called? if not check the return value of IOleObject::SetClientSite

      1. Yes they are called.

        I use ShowContextMenu() and GetHostInfo() to change webbrowser control’s behaviour.

      2. Actually I can successfully query the interface as follows. However, webbrowser control does not query.

        CComPtr pServiceProvider;
        hr = m_wb->QueryInterface(IID_IServiceProvider, (LPVOID*)&pServiceProvider);
        if (SUCCEEDED(hr)){
        CComPtr pHTTPSecurity;
        hr = pServiceProvider->QueryService(IID_IHttpSecurity, IID_IHttpSecurity, (LPVOID*) &pHTTPSecurity);
        if (SUCCEEDED(hr)){
        pHTTPSecurity->OnSecurityProblem(0);
        }
        }

  4. Worked great for letting me debug Excel VSTO against local web server, thanks

    1. No. WPF’s WebBrowser class does not provide a public virtual function to change the ActiveX site.

  5. Thank you very much, this works just fine.
    by the way I had to change in Form1.Designer.cs this
    ///
    /// Required method for Designer support – do not modify
    /// the contents of this method with the code editor.
    ///
    private void InitializeComponent()
    {
    this.webBrowser1 = new WindowsFormsApplication1.MyWebBrowser();

  6. Hi i used the same code, developed using C# forms client, first time when the web browser loads the web page(expired certificate), i am getting sercurity alert dialog. From second time onwards, i am not getting the dialog box. While loading for the first time, control is not reaching OnSecurityProblem() function.

    Below is C# snippet.

    public class MyWebBrowser : WebBrowser
    {
    public static Guid IID_IHttpSecurity = new Guid(“79eac9d7-bafa-11ce-8c82-00aa004ba90b”);
    public static Guid IID_IWindowForBindingUI = new Guid(“79eac9d5-bafa-11ce-8c82-00aa004ba90b”);
    public const int S_OK = 0;
    public const int S_FALSE = 1;
    public const int E_NOINTERFACE = unchecked((int)0x80004002);
    public const int RPC_E_RETRY = unchecked((int)0x80010109);
    protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
    {
    return new MyWebBrowserSite(this);
    }
    class MyWebBrowserSite : WebBrowserSite,
    UCOMIServiceProvider,
    IHttpSecurity,
    IWindowForBindingUI
    {
    private MyWebBrowser myWebBrowser;
    public MyWebBrowserSite(MyWebBrowser myWebBrowser)
    : base(myWebBrowser)
    {
    this.myWebBrowser = myWebBrowser;
    }
    public int QueryService(ref Guid guidService
    , ref Guid riid
    , out IntPtr ppvObject)
    {
    if (riid == IID_IHttpSecurity)
    {
    ppvObject = Marshal.GetComInterfaceForObject(this
    , typeof(IHttpSecurity));
    return S_OK;
    }
    if (riid == IID_IWindowForBindingUI)
    {
    ppvObject = Marshal.GetComInterfaceForObject(this
    , typeof(IWindowForBindingUI));
    return S_OK;
    }
    ppvObject = IntPtr.Zero;
    return E_NOINTERFACE;
    }
    public int GetWindow(ref Guid rguidReason
    , ref IntPtr phwnd)
    {
    if (rguidReason == IID_IHttpSecurity
    || rguidReason == IID_IWindowForBindingUI)
    {
    phwnd = myWebBrowser.Handle;
    return S_OK;
    }
    else
    {
    phwnd = IntPtr.Zero;
    return S_FALSE;
    }
    }
    public int OnSecurityProblem(uint dwProblem)
    {
    //ignore errors
    //undocumented return code, does not work on IE6
    return S_OK;
    }
    }
    }

    1. hmm try navigate to about:blank first?

      1. thank you, i need to navigate once to ‘about:blank’ first, then only i am getting IID_IWindowForBindingUI interface object. Once the binding happens it is working fine,

  7. Works like a charm! Thanks Sheng

  8. Hello,
    How can we implement this in MFC.
    I have derived a class using CHTMLView and how can I ignore web browser certificate for particular URL?

      1. Hello,
        I have implemented OnSecurityProblem().
        It resolve my problem of SSL Certificate authentication issue.
        but now I am getting HTTP redirection issue.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.