.NET WebBrowser 粘贴安全限制

.NET WebBrowser Paste Security Restriction

我在 C# WPF 应用程序中使用 WebBrowser 控件。我需要以编程方式执行粘贴命令,我使用以下语句执行此操作:

WebBrowser.Document.ExecCommand("paste", false, null);

这在我的本地机器上完美运行;但是,它在我们的生产环境中不起作用。该命令什么都不做。幸运的是,基于 this post.

,我确定此问题的原因是 IE 安全限制

修复方法是将 IE 中的安全级别修改为中等(工具 > Internet 选项 > 安全 > Internet > 中等级别)。

按照 post 的回答,问题可以解决。但是在我们的生产环境中,IE的安全设置是高的,因为安全策略的原因是不能修改的。因此无法使用此修复程序。

我看到另一个 post 关于添加自定义安全管理器,这听起来像是解决这个问题的可能方法。

但是,我无法准确确定我需要实施哪些 IInternetSecurityManager 方法或如何实施它们。我已经定义了接口并获得了要调用的方法,但我目前只是为所有这些方法返回 INET_E_DEFAULT_ACTION。

public class MyWebBrowser : WebBrowser
{

    protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
    {
        return new ExtendedWebBrowserSite(this);
    }

    protected class ExtendedWebBrowserSite : WebBrowserSite, IInternetSecurityManager, IServiceProvider
    {
        private static readonly Guid SID_IInternetSecurityManager = new Guid("79EAC9EE-BAF9-11CE-8C82-00AA004BA90B");

        WebBrowser _host;

        public ExtendedWebBrowserSite(WebBrowser host) : base(host)
        {
            _host = host;
        }

        public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
        {
            if (guidService == SID_IInternetSecurityManager && riid == SID_IInternetSecurityManager)
            {
                ppvObject = Marshal.GetComInterfaceForObject(this, typeof(IInternetSecurityManager));
                return HRESULTS.S_OK;
            }
            ppvObject = IntPtr.Zero;
            return HRESULTS.E_NOINTERFACE;
        }

        #region IInternetSecurityManager Implementation

        public int SetSecuritySite([In] IntPtr pSite)
        {
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int GetSecuritySite([Out] IntPtr pSite)
        {
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int MapUrlToZone([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, out uint pdwZone, uint dwFlags)
        {
            pdwZone = 0;
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int GetSecurityId([MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, [MarshalAs(UnmanagedType.LPArray)] byte[] pbSecurityId, ref uint pcbSecurityId, uint dwReserved)
        {
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int ProcessUrlAction([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, uint dwAction, out byte pPolicy, uint cbPolicy, byte pContext, uint cbContext, uint dwFlags, uint dwReserved)
        {
            pPolicy = 0;
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int QueryCustomPolicy([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, ref Guid guidKey, ref byte ppPolicy, ref uint pcbPolicy, ref byte pContext, uint cbContext, uint dwReserved)
        {
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int SetZoneMapping(uint dwZone, [In, MarshalAs(UnmanagedType.LPWStr)] string lpszPattern, uint dwFlags)
        {
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }

        public int GetZoneMappings(uint dwZone, out IEnumString ppenumString, uint dwFlags)
        {
            ppenumString = null;
            return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
        }


        #endregion IInternetSecurityManager Implementation
    }
}

我应该实施哪些方法来修复粘贴功能,如何实施?

好的,我相信我已经弄明白了。我有一个解决问题的实现,虽然我还没有彻底测试它,所以它可能有也可能没有一些不需要的副作用。

如果您扩展 WebBrowser 控件(我们称它为 MyWebBrowser)然后覆盖 CreateWebBrowserSiteBase 方法,您可以提供您自己的 WebBrowserSite 派生的 class(我们称它为 ExtendedWebBrowserSite)来实现必要的 COM 接口(在本例中,IServiceProviderIInternetSecurityManager)。

然后在 ExtendedWebBrowserSite class 中,我们需要实现 IServiceProvider.QueryService 方法,这样它将 return IInternetSecurityManager 的正确实现。然后我们还需要实现 IInternetSecurityManager 的所有方法。这里重要的方法是IInternetSecurityManager.ProcessUrlAction,需要覆盖默认逻辑。其余的 IInternetSecurityManager 方法只需要 return INET_E_DEFAULT_ACTION, to ensure that the default security manager handles those actions. The IInternetSecurityManager.ProcessUrlAction method should check if the action is URLACTION_SCRIPT_PASTE. If it is, then we should set the pPolicy out parameter to URLPOLICY_ALLOW and return S_OK. Otherwise, we should return INET_E_DEFAULT_ACTION. I'm pretty sure that if we return INET_E_DEFAULT_ACTION,将 pPolicy 设置为什么值并不重要,因为它会被忽略。如果我在这里错了,请纠正我。

我的网络浏览器:

class MyWebBrowser : System.Windows.Forms.WebBrowser
{
    protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
    {
        return new ExtendedWebBrowserSite(this);
    }
}

ExtendedWebBrowserSite:

class ExtendedWebBrowserSite : WebBrowserSite, IInternetSecurityManager, IServiceProvider
{

    // constructor omitted

    int IServiceProvider.QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
    {
        if (guidService == SID_IInternetSecurityManager && riid == SID_IInternetSecurityManager)
        {
            ppvObject = Marshal.GetComInterfaceForObject(this, typeof(IInternetSecurityManager));
            return HRESULTS.S_OK;
        }
        ppvObject = IntPtr.Zero;
        return HRESULTS.E_NOINTERFACE;
    }

    int IInternetSecurityManager.ProcessUrlAction([In, MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, uint dwAction, out byte pPolicy, uint cbPolicy, byte pContext, uint cbContext, uint dwFlags, uint dwReserved)
    {
        // If action is a paste, then we want to allow it, regardless of the inherited IE security policy.
        if (dwAction == URLActionFlags.URLACTION_SCRIPT_PASTE)
        {
            pPolicy = URLPolicyFlags.URLPOLICY_ALLOW;
            return HRESULTS.S_OK;
        }

        // I think we can set the policy to whatever arbitrary value we want here. 
        // Because if we return INET_E_DEFAULT_ACTION, the policy value will just be ignored.
        pPolicy = URLPolicyFlags.URLPOLICY_ALLOW;
        return URLMonikerErrorCodes.INET_E_DEFAULT_ACTION;
    }

    // Other IInternetSecurityManager methods omitted for brevity...
    // Other IInternetSecurityManager methods should all return INET_E_DEFAULT_ACTION to ensure that the default security manager handles them.
}

COM 接口定义

[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
    [PreserveSig]
    int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject);
}
[ComImport, Guid("79EAC9EE-BAF9-11CE-8C82-00AA004BA90B")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IInternetSecurityManager
{
    [PreserveSig] 
    int SetSecuritySite([In] IntPtr pSite);

    [PreserveSig] 
    int GetSecuritySite([Out] IntPtr pSite);

    [PreserveSig] 
    int MapUrlToZone([In,MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, out UInt32 pdwZone, UInt32 dwFlags);

    [PreserveSig] 
    int GetSecurityId([MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, [MarshalAs(UnmanagedType.LPArray)] byte[] pbSecurityId, ref UInt32  pcbSecurityId, uint dwReserved);

    [PreserveSig] 
    int ProcessUrlAction([In,MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, UInt32 dwAction, out byte pPolicy, UInt32 cbPolicy, byte pContext, UInt32 cbContext, UInt32 dwFlags, UInt32 dwReserved);

    [PreserveSig]
    int QueryCustomPolicy([In,MarshalAs(UnmanagedType.LPWStr)] string pwszUrl, ref Guid guidKey, ref byte ppPolicy, ref UInt32 pcbPolicy, ref byte pContext, UInt32 cbContext, UInt32 dwReserved);

    [PreserveSig]
    int SetZoneMapping(UInt32 dwZone, [In,MarshalAs(UnmanagedType.LPWStr)] string lpszPattern, UInt32 dwFlags);

    [PreserveSig]
    int GetZoneMappings(UInt32 dwZone, out IEnumString ppenumString, UInt32 dwFlags);
}