剖析ActiveX控件安全问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剖析ActiveX控件安全问题相关的知识,希望对你有一定的参考价值。

Dissect ActiveX Control Safety

1、介绍

        如果你曾经在网页或者ASP中使用过com对象,你可能会发现,有时候会出现这样讨厌的对话框

 技术分享

     这是因为你的控件没有被标记为安全的,对于初始化不安全或者对于脚本不安全,甚至兼而有之。你每打开一次这样的网页,这种情况就会发生一次,你怎么办?当然,这可以通过设置IE本身的安全等级为low来解决这样的问题,但是如果你要制作一个可发布的控件,你能想象到每一位用户在使用你制作的控件时都要且列抱怨这种强制行为;或者如果你是其中一个使用者,当你同样遇到这种情况之后不得不将自己的IE安全等级设置为low,与此同时你平时上网过程中那些行为不轨的控件有时也会悄然而至,你的灾难来了!作为一个聪明的程序员,你不能要求任何用户做一些不切实际或者不够安全的改变来适应你的产品,因为你知道那只会使你的控件被逐渐打入冷宫,到最后销声匿迹,那不是你想要的。我们要消灭掉这样的对话框而且还不让用户发现丝毫安全上和使用上的失望。本文就是横向探讨在C++编程环境下如何消除这些问题的。

2、原理

     ActiveX控件是一种极其危险的提供功能的方法(目前正在被MS逐渐冷落),因为它是一种组建对象模型(COM)的对象,只要电脑的用户可以完成的任务,它都可以完成。比如它可以存取注册表,可以随意访问本地文件系统等等。一个网页上面的控件一般有2种不安全的状态,一种是脚本的不安全,一种是初始化的不安全。当用户将一个压缩解压缩控件指向一个远程被压缩的包含特洛伊木马的系统文件并且需要控件来解压缩这个文件时,系统安全会被打破。这个状态就是初始化的不安全。从代码的角度来讲,如果控件从IPersist派生,也就是说控件实现了永久性,那么就会触发unsafe for initializing。而在脚本程序安全执行以前,一个控件依赖于特定的系统设置,那么在允许这段代码运行之前,控件的开发人员需要提供一些必要的代码。从代码的角度来讲,如果控件从IDispatch派生,也就是说控件支持脚本,那么就会触发unsafe for scripting。

     从用户下载一个ActiveX控件开始,这个控件甚至可能很容易被攻击,因为网络上任何网络程序都可以使用它,无论是出于友好的目的还是恶意的目的。因此IE浏览器(本文只探讨IE内核的浏览器)总是试图弹出一个对话框来告诉你,这个控件可能是不安全的。这几乎总是一个很好的预防网络攻击的好方法,但是对于那些我们认为总是安全的控件,我们仍然要总是接受这种IE产生的干扰,这就使人厌烦了。其实当身为程序员的你写这样的安全控件时,这样的问题是很容易解决的。

3、解决方法

     目前,对这个问题的解决方法主要有几种:使用数字签名,继承IObjectSafety接口,修改注册表等。

3.1、使用数字签名

     数字签名是一种使控件足够安全的方法,它通过特定的密钥来加密控件的使用,使得使用控件的对象能够根据密钥是否相符来检测控件是否足够安全。通常,拥有自己的可发布的数字签名是要Money的,本文是一篇技术文章,对此并不深入探讨,下面主要介绍代码方面的安全化。

3.2、继承IObjectSafety接口

     IObjectSafety接口是在头文件"objsafe.h"中定义的接口,定义如下:

技术分享IObjectSafety : public IUnknown 技术分享

     其中参数意义如下:

技术分享//riid                Interface identifier for the object to be made safe.  技术分享// 技术分享//dwOptionSetMask     Options to be changed.  技术分享// 技术分享//dwEnabledOptions    Settings for the options that are to be changed. This can be one of the following values.  技术分享//                    INTERFACESAFE_FOR_UNTRUSTED_CALLER 技术分享//                        Indicates the interface identified by riid should be made safe for scripting.  技术分享//                    INTERFACESAFE_FOR_UNTRUSTED_DATA 技术分享//                        Indicates the interface identified by riid should be made safe for untrusted data during initialization. 技术分享

     这个接口允许容器询问控件是否安全或者改变控件的安全属性。目前IObjectSafety支持四种安全属性,但是一般我们只使用前两个:脚本安全和初始化安全。这些属性定义如下:

技术分享// Option bit definitions for IObjectSafety: 技术分享#define    INTERFACESAFE_FOR_UNTRUSTED_CALLER        0x00000001    // Caller of interface may be untrusted 技术分享#define    INTERFACESAFE_FOR_UNTRUSTED_DATA             0x00000002    // Data passed into interface may be untrusted 技术分享#define    INTERFACE_USES_DISPEX                                             0x00000004    // Object knows to use IDispatchEx 技术分享#define    INTERFACE_USES_SECURITY_MANAGER                0x00000008    // Object knows to use IInternetHostSecurityManager

3.2.1、实现方法

     首先包含头文件

技术分享#include "objsafe.h"

     然后是自己的控件类继承IObjectSafetyImpl

技术分享class YourClass : 技术分享    技术分享 技术分享    public IObjectSafetyImpl<YourClass, INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA> 技术分享

     其中INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA 代表默认这个控件是脚本安全而且初始化安全的。然后在com接口表中添加接口名

技术分享BEGIN_COM_MAP(CCGrid) 技术分享    技术分享 技术分享    COM_INTERFACE_ENTRY(IObjectSafety) 技术分享END_COM_MAP() 技术分享

     OK,大功告成。这也是一种很简单的方法。

3.3、修改注册表

     修改注册表项使控件支持安全类别的原理,归根到底其实就是下面的第三个方法,另外两个方法都是对这个方法的外围包装和更加安全的处理。修改注册表在不同的工程中有着不同的表现:

3.3.1、用于ATL属性工程的com接口

     因为VC的属性工程已经加入了安全控件的注册表支持,并且直接加入了关键字implements_category,因此我们仅仅象下面这样既可完成安全属性设置:

技术分享[ 技术分享    coclass/progid/vi_prgid,            //必须至少有其中一个 技术分享    技术分享 技术分享    implements_category("CATID_SafeForScripting"), 技术分享    implements_category("CATID_SafeForInitializing"), 技术分享    技术分享 技术分享] 技术分享

     不过要注意的是,对于类似下面的代码(往往是非属性工程的)是不能添加的:

技术分享[ 技术分享    uuid(技术分享), 技术分享    helpstring("") 技术分享] 技术分享coclass YourCtrl 技术分享

     因为这种coclass是IDL的属性,而IDL本身并没有安全功能。

     而上面的那种coclass是VC的属性,MS提供了对安全控件的支持。

3.3.2、主要用于非属性工程的通用方法

     在类声明文件中加入头文件

技术分享#include "objsafe.h"技术分享

     在类声明中添加如下代码:

技术分享    BEGIN_CATEGORY_MAP( YourCtrlClassName ) 技术分享       IMPLEMENTED_CATEGORY( CATID_SafeForScripting ) 技术分享       IMPLEMENTED_CATEGORY( CATID_SafeForInitializing ) 技术分享   END_CATEGORY_MAP()

     即可使其支持safety属性,当然你也可以选择性的只支持一种安全属性。

3.3.3、主要用于MFC ActiveX Control的通用方法

     在$project.cpp文件中添加以下代码:

技术分享#include "comcat.h" 技术分享#include "Objsafe.h" 技术分享 技术分享// 控件的CLSID,注册表用(一定要是实际使用的控件的) 技术分享const GUID CDECL CLSID_SafeItem =

     修改以下函数:

技术分享// DllRegisterServer - Adds entries to the system registry 技术分享STDAPI DllRegisterServer(void) 技术分享

     至此对工程的修改完成了,现在控件就可以在自注册时就注册为安全控件了!

3.3.4、手动修改注册表

     我们可以自己手动为控件在注册表中添加安全支持,实际上我们所需要的两个项(Key)就是这样的形式:

技术分享\\HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\<GUID of control class>\\Implemented Categories\\<GUID of category>

     ActiveX SDK头文件ObjSafe.H 已经为类别CATID_SafeForInitializing和CATID_SafeForScripting定义了GUID值。因此对于特定的工程,如果控件类的GUID是{20048BB3-DB68-11CF-9CAF-00AA006CB425},那么我们就只需要添加两个注册表项:  

技术分享   REGEDIT4 技术分享        技术分享   [HKEY_CLASSES_ROOT\\CLSID\\

以上是关于剖析ActiveX控件安全问题的主要内容,如果未能解决你的问题,请参考以下文章

IE安全限制

你的浏览器已经阻止此站点用不安全方式使用ActiveX控件

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

浏览器提示已经阻止此站点以不安全的方式使用ActiveX 控件,怎么解决?

如何开发ActiveX控件

基于MFC的ActiveX控件开发教程------------浏览器插件之ActiveX开发