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.

About Sheng Jiang 蒋晟

Microsoft MVP in Visual C , 2004- Forum moderator of the Visual C and .Net forums on CSDN Forum moderator of Chinese forums on Microsoft's MSDN forums
This entry was posted in C#, MFC, Microsoft, Visual Studio, Webbrowser control and tagged , , , , , . Bookmark the permalink.

8 Responses to Howto: Ignoring web browser certificate errors in a webbrowser host

  1. uchida_t says:

    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!

  2. Sergio says:

    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

  3. Ömer Özer says:

    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()

    }

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

      • Ömer Özer says:

        Yes they are called.

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

      • Ömer Özer says:

        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. Willma says:

    u made my day🙂

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 )

Google+ photo

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

Connecting to %s