是否可以将 ActiveX 对象标记为安全以便无需更改 IE 设置?

Posted

技术标签:

【中文标题】是否可以将 ActiveX 对象标记为安全以便无需更改 IE 设置?【英文标题】:Is it possible to mark an ActiveX object as safe so that IE settings need not be changed? 【发布时间】:2014-01-15 11:29:04 【问题描述】:

我创建了一个启动应用程序的 ActiveX dll 程序集。我在浏览器中通过 javascript 调用了这个 dll。该应用程序在点击 URL 时启动。

要让这个脚本工作,我需要进入 IE 设置并启用“初始化和脚本未标记为安全的 activex 控件”。有没有办法对 ActiveX 对象进行编码以将其标记为安全?

我用SN工具生成了一个key(.snk文件),用这个key编译了DLL。因此,该 dll 已签名,但它不会运行,除非我在 IE 设置中启用“初始化并编写未标记为安全的脚本 Activex 控件”。

这是我已经实现并希望将其标记为安全的文章:- Writing an ActiveX control in C#。

我在 this microsoft link:-

上获得了对安全控制概念 (IObjectSafety) 的参考

我无法理解该代码需要放在哪里。任何帮助都会使其更清楚..

【问题讨论】:

【参考方案1】:

我从不同的地方收集了一些代码(和知识),这是我的工作版本 - 界面

    [Serializable, ComVisible(true)]
    public enum ObjectSafetyOptions
    
        INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001,
        INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002,
        INTERFACE_USES_DISPEX = 0x00000004,
        INTERFACE_USES_SECURITY_MANAGER = 0x00000008
    

    //
    // MS IObjectSafety Interface definition
    //
    [
        ComImport(),
        Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"),
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
    ]
    public interface IObjectSafety
    
        [PreserveSig]
        long GetInterfaceSafetyOptions(ref Guid iid, out int pdwSupportedOptions, out int pdwEnabledOptions);

        [PreserveSig]
        long SetInterfaceSafetyOptions(ref Guid iid, int dwOptionSetMask, int dwEnabledOptions);
    

和实施

    #region safe for scripting
    private ObjectSafetyOptions m_options = ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_CALLER | ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_DATA;
    public long GetInterfaceSafetyOptions(ref Guid iid, out int pdwSupportedOptions, out int pdwEnabledOptions)
    
        pdwSupportedOptions = (int)m_options;
        pdwEnabledOptions = (int)m_options;
        return 0;
    

    public long SetInterfaceSafetyOptions(ref Guid iid, int dwOptionSetMask, int dwEnabledOptions)
    
        return 0;
    
    #endregion safe for scripting

现在 IE 不会用确认对话框来唠叨我了。

【讨论】:

【参考方案2】:

以下链接有一个完美的示例,它是创建以及将 activeX 控件标记为安全的答案:-Creating activex objects with c#

用c#创建activex对象

本指南的目的是提供简单的步骤 创建一个可以在 IE 中加载和使用的简单 ActiveX 控件 托管网页。

背景

ActiveX 是一种 Microsoft 技术,用于创建 可重复使用的组件。这种技术,也称为对象链接和嵌入 (OLE) 以及 COM 在 Microsoft 环境中被大量使用,并且 应用程序开发。在本文中,我将使用该术语 COM 包含所有类似的 Microsoft 相关技术:ActiveX、OLE、 自动化等……因为它是创建组件的框架。任何人 对创建可重用组件感兴趣的应该熟悉 通讯。一个非常好的资源是 Don Box 的“Essential COM”。

COM 背后的想法是允许创建组件 可以被各种客户消费。这意味着我可以创建一个 使用 C++ 的组件,然后可以由用 VB 编写的应用程序使用,或 甚至是我们将很快执行的网页。传统上,ActiveX 对象通常用 C++ 和 VB 编写,但实际上可以用任何 语言,只要它们能够识别 COM。

这意味着我们可以使用 .NET 创建 COM 对象 平台。和 large 只告诉你如何通过 Interop 使用非托管 COM 对象。所以我的目标 本指南旨在展示如何使用这个强大的功能。另外,仅供参考,有 一种 .NET 技术,与下面将要描述的非常相似,它允许 在 IE 中托管 Windows 窗体控件(不知道官方术语/名称 为此)。

废话不多说,让我们开始示例吧。

要求

熟悉 C#。

开发环境。我将使用 Visual Studio

    (2003 应该也可以。不过不知道速成版。)

html、Javascript

IE。 ActiveX 对象不能托管在任何其他 浏览器。

创建 ActiveX 控件

第一步是创建一个 C# DLL 项目。这可以是 完成以下步骤:

    启动 Visual Studio 选择文件 -> 新建项目 为项目类型选择“其他语言”->“Visual C#” 选择“类库”模板

创建项目后,继续重命名 Class1.cs 随心所欲。我将其重命名为 HelloControl.cs

我们将创建的 ActiveX 控件是无处不在的 你好世界!代码和解释如下。

HelloControl.cs

    using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text;

namespace csharp.activex.sample

    /// <summary>
    /// A very simple interface to test ActiveX with.
    /// </summary>
    [
        Guid( "E86A9038-368D-4e8f-B389-FDEF38935B2F"),
        InterfaceType( ComInterfaceType.InterfaceIsDual),
        ComVisible( true)
    ]
    public interface IHello
    
        [DispId(1)]
        string Hello();

        [DispId(2)]
        int ShowDialog(string msg);
    ;

    [
        Guid("873355E1-2D0D-476f-9BEF-C7E645024C32"),

        // This is basically the programmer friendly name
        // for the guid above. We define this because it will
        // be used to instantiate this class. I think this can be
        // whatever you want. Generally it is
        // [assemblyname].[classname]
        ProgId("csharpAx.CHello"),

        // No class interface is generated for this class and
        // no interface is marked as the default.
        // Users are expected to expose functionality through
        // interfaces that will be explicitly exposed by the object
        // This means the object can only expose interfaces we define
        ClassInterface(ClassInterfaceType.None),

        // Set the default COM interface that will be used for
        // Automation. Languages like: C#, C++ and VB
        // allow to query for interface's we're interested in
        // but Automation only aware languages like javascript do
        // not allow to query interface(s) and create only the
        // default one
        ComDefaultInterface(typeof(IHello)),
        ComVisible(true)
    ]
    public class CHello : IHello
    

        #region [IHello implementation]
        public string Hello()
        
            return "Hello from CHello object";
        


        public int ShowDialog(string msg)
        
            System.Windows.Forms.MessageBox.Show(msg, "");
            return 0;
        
        #endregion
    ;

HelloControl.cs 文件由一个类和一个接口组成。 那么让我们从接口定义开始,接着是 CHello 类。

IHello 接口

接口通常被描述为契约。一旦设计了界面 并发布使用它不应该改变。让我重复一遍,它 永远不会改变。

已经为这个接口定义了几个属性。

1) Guid – 这是一个唯一标识符。使用 guidgen.exe 生成自己的 2) InterfaceType – 这决定了向 COM 公开哪个基类。

InterfaceType 属性需要进一步解释。这是它的定义方式。

public enum ComInterfaceType

    InterfaceIsDual = 0,
    InterfaceIsIUnknown = 1,
    InterfaceIsIDispatch = 2,

所有 COM 接口和对象必须至少继承 IUnknown 接口(见附录 A)。该接口允许客户端创建 COM 对象通过 CoCreateInstance() 并搜索其他接口以及 处理对象生命周期管理。

IDispatch 接口只允许在自动化感知中使用对象 像javascript这样的语言(见附录B)。这个接口,允许客户端 应用程序来查询对象在运行时支持的属性和方法- 时间并执行它们。这很像 .Net 中的反射。

Dual 仅表示上述两者的组合。这样做的主要原因是 允许在没有 IDispatch 的所有开销的情况下创建接口 在不需要的情况下。

最后,您会注意到 IHello 中每个方法的 DispId(#) 属性 界面。从 IDispatch 接口调用 Invoke 时需要这样做。

CHello 类

最后要讨论的是 CHello 类。这个类简单实现 IHello 接口仅此而已。 ShowDialog() 只是表明我们可以 执行需要某种 UI 的对象,在本例中为消息框。 属性在 cmets 中进行了描述。

编译和注册

编写完代码后,继续编译 ActiveX 程序集。 该程序集将在项目的 bin 文件夹中称为 [projectname].dll。

下一步是注册。这样做会打开一个命令提示符并转到 dll的位置。注册程序集类型:

C:\Regasm [项目名称].dll /codebase /tlb

确保将“[projectname]”替换为您的 dll 的正确名称。 您应该得到一些输出,表明程序集已正确导出。 类似于以下内容。

Microsoft ® .NE​​T Framework 程序集注册实用程序 2.0.50727.42 版权所有 © 微软公司 1998-2004。版权所有。 类型注册成功 程序集导出到 '[TLB 位置] ',类型库注册成功

要取消注册程序集,请将“/unregister”标志传递给 Regasm。您将需要 当需要对程序集进行更改时,取消注册并关闭 IE。如果你不 在进行代码更改之前取消注册您的程序集,您最终可能会得到虚假 注册表项和清理的痛苦。关闭 IE 的原因是为了确保 对您的程序集的所有引用都已被释放。

创建 HTML 测试页

我们即将完成。我们现在需要做的就是创建一个测试页面。 这应该很简单,但仍然如此。 Javascript 还提供了创建 ActiveX 对象的方法。

Test.html

<html xmlns="http://www.w3.org/1999/xhtml">
<head> <title>C# ActiveX Test</title> </head>

<body onload="myload();">
<h1>This is Our ActiveX Test Page h1>

The message from the ActiveX Control is [
<div id="axmsg"></div>
]

<script type ="text/javascript">
function myload()

    var myAx = new ActiveXObject("csharpAx.CHello");
    if(myAx != null)
    
        myAx.ShowDialog("hello from asp.net"); 
        var d = document.getElementById("axmsg");

        var s = myAx.Hello();
        d.outerText = s;
    
    else
        lert("NOOOO... we failed");

</script>
</body></html>

要在 Javascript 中创建我们的 ActiveX 对象,我们使用 ActiveXObject()。参数 因为这通常是我们在其定义中指定的 PROGID。如果一个 PROGID 未在其定义中指定,那么我认为您可以传入 “AssemblyName.ClassName”。其余的 javascript 只是简单地调用我们的 ActiveX 对象方法。

就是这样!!!我们应该有一个功能齐全的例子。这种执行 ActiveX 的能力 来自 javascript 的对象非常强大。关于安全的辩论和争论 ActiveX 对象的安全性是众所周知的,我不会再扔更多的饲料 到火。但是,想象一下创建一个 Win32 甚至是 Winform 应用程序 UI 是通过 IWebBrowser2 用 HTML 编写的,并且所有 UI 交互都已处理 与您的 ActiveX 对象,只是深思熟虑。虽然,现在想起来, WPF 已经在这样做了。哦,好吧。

希望这份关于如何使用 C# 创建 ActiveX 对象的指南对您有所帮助。

-skaoth-

进一步修改

上面的例子虽然完整(希望没有错误),但有一个小问题。当html页面是 加载后我们得到一个讨厌的消息框说

“此页面上的 ActiveX 控件可能不安全……等等等等”

那么我们该如何解决这个问题呢?好吧,这真的很简单。我们需要实现一个接口 称为 IObjectSafety。为此,请将新的 .cs 文件添加到项目中。

IObjectSafety.cs

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Text;

namespace csharp.activex.sample

    [
        Serializable,
        ComVisible(true)
    ]
    public enum ObjectSafetyOptions
    
        INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001,
        INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002,
        INTERFACE_USES_DISPEX = 0x00000004,
        INTERFACE_USES_SECURITY_MANAGER = 0x00000008
    ;

    //
    // MS IObjectSafety Interface definition
    //
    [
        ComImport(),
        Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"),
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
    ]
    public interface IObjectSafety
    
        [PreserveSig]
        long GetInterfaceSafetyOptions( ref Guid iid, out int pdwSupportedOptions, out int pdwEnabledOptions);

        [PreserveSig]
        long SetInterfaceSafetyOptions( ref Guid iid, int dwOptionSetMask, int dwEnabledOptions);
    ;

    //
    // Provides a default Implementation for
    // safe scripting.
    // This basically means IE won't complain about the
    // ActiveX object not being safe
    //
    public class IObjectSafetyImpl : IObjectSafety
    
        private ObjectSafetyOptions m_options =
            ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_CALLER | 
            ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_DATA;

        #region [IObjectSafety implementation]
        public long GetInterfaceSafetyOptions( ref Guid iid, out int pdwSupportedOptions, out int pdwEnabledOptions)
        
            pdwSupportedOptions = (int)m_options;
            pdwEnabledOptions = (int)m_options;
            return 0;
        

        public long SetInterfaceSafetyOptions(ref Guid iid, int dwOptionSetMask, int dwEnabledOptions)
        
            return 0;
        
        #endregion
    ;

然后修改CHello对象,使其继承自IObjectSafetyImpl 类,使其看起来像

public class CHello : IObjectSafetyImpl, IHello

…
;

这样,关于 ActiveX 对象不安全的对话框应该会消失。

参考文献

ATL 内部 - Brent E. Rector,Chris Sells。 Essential COM – Don Box。

http://msdn2.microso...yw6(VS.80).aspx http://msdn2.microso...y/aa768224.aspx http://www.c-sharpco...tiveXInNet.aspx

附录 A:未知

interface IUnknown

virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) = 0;
virtual ULONG AddRef(void) = 0;
virtual ULONG Release(void) = 0;

;

附录 B:IDispatch

interface IDispatch : public IUnknown

virtual ULONG GetTypeInfoCount(unsigned int FAR* pctinfo) = 0;
virtual HRESULT GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo ) = 0;
virtual ULONG GetIDsOfNames(
REFIID riid,
OLECHAR FAR* FAR* rgszNames,
unsigned int cNames,
LCID lcid,
DISPID FAR* rgDispId) = 0;
virtual ULONG Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS FAR* pDispParams,
VARIANT FAR* pVarResult,
EXCEPINFO FAR* pExcepInfo,
unsigned int FAR* puArgErr) = 0;
; 

【讨论】:

贴出的链接建议的解决方案对我不起作用,我还是要修改IE配置

以上是关于是否可以将 ActiveX 对象标记为安全以便无需更改 IE 设置?的主要内容,如果未能解决你的问题,请参考以下文章

用js或者java如何实现将IE的安全设置“不允许运行未标记为安全的activeX控件”设置为启用

剖析ActiveX控件安全问题

IE安全限制

有没有办法将雪花视图标记为“安全”以便结果重用?

打开网页显示“该插件没有正常初始化”

ActiveX控件自动更新,数字签名突破IE安全限制