보안문제 해결하기

ActiveX 컨트롤 IE에서 보여주기 위해 사용하는 경우에 보안관련 메세지 박스들이 나타나게 된다. 이 컨트롤 자체가 신뢰할 수 있는 제작사 또는 개발자에 의해서 개발된 것인가 하는 것과 ActiveX 컨트롤에 매개변수를 넘기는 경우와 같이 ActiveX 스크립트를 사용하는 경우에는 안전한 스크립트인지 확인하라는 경우이다.
전자는 code signing을 통해 보장받을 수 있으며, 후자의 경우는 IObjectSafefy 인터페이스를 구현함으로써 보장받을 수 있다.
전자의 경우는 VeriSign에서 몇백달러를 지불하는데, 시험용이나 개인개발자들은 시험용 인증서를 만들어서 사용할 수 있다.
지금 여기서는 후자의 경우 해결방안에 대해서 기술하고자 한다.

Test라는 이름으로 구현해보자!



cathelp.cpp와 cathelp.h를 프로젝트에 포함시킨 후,
DllRegisterServer()를 다음과 같이 수정한다.


STDAPI DllRegisterServer(void)
{
        HRESULT hr = NOERROR;
        AFX_MANAGE_STATE(_afxModuleAddrThis);

        if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
                return ResultFromScode(SELFREG_E_TYPELIB);

        if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
                return ResultFromScode(SELFREG_E_CLASS);

        hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls that are safely scriptable");
        if (FAILED(hr))
        {
                ;//                OutputDebugString("Failed to create component category (scriptable)!n");
        }

        hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data");
        if (FAILED(hr))
        {
                ;//                OutputDebugString("Failed to create component category (persistence)!n");
        }

        hr = RegisterCLSIDInCategory(CTestCtrl::guid, CATID_SafeForScripting);
        if (FAILED(hr))
        {
                ;//                OutputDebugString("Failed to register control as safe for scripting!n");
        }

        hr = RegisterCLSIDInCategory(CTestCtrl::guid, CATID_SafeForInitializing);
        if (FAILED(hr))
        {
                ;//                OutputDebugString("Failed to register control as safe for initializing!n");
        }

        return NOERROR;
}

DllUnregisterServer()를 아래와 같이 수정한다.

STDAPI DllUnregisterServer(void)
{
        AFX_MANAGE_STATE(_afxModuleAddrThis);

        if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))
                return ResultFromScode(SELFREG_E_TYPELIB);

        if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))
                return ResultFromScode(SELFREG_E_CLASS);

        HRESULT hr = NOERROR;
        hr = UnRegisterCLSIDInCategory(CTestCtrl::guid, CATID_SafeForScripting);
        hr = UnRegisterCLSIDInCategory(CTestCtrl::guid, CATID_SafeForInitializing);

        return NOERROR;
}

컨트롤이름ctrl.h 파일에 objsafe.h을 include한다.
그리고, 아래와 같이 추가한다.


class CTestCtrl : public COleControl
{
        DECLARE_DYNCREATE(CTestCtrl)

        BEGIN_INTERFACE_PART(ObjectSafety, IObjectSafety)
                STDMETHOD(GetInterfaceSafetyOptions)(REFIID riid, DWORD __RPC_FAR *pdwSupportedOptions, DWORD __RPC_FAR *pdwEnabledOptions);
                STDMETHOD(SetInterfaceSafetyOptions)(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions);
        END_INTERFACE_PART(ObjectSafety)

        DECLARE_INTERFACE_MAP();

마지막으로 cpp파일에 다음을 추가하면 된다.

STDMETHODIMP CTestCtrl::XObjectSafety::GetInterfaceSafetyOptions(
                        REFIID riid,
                        DWORD __RPC_FAR *pdwSupportedOptions,
                        DWORD __RPC_FAR *pdwEnabledOptions)
{
        METHOD_PROLOGUE_EX(CTestCtrl, ObjectSafety)

        if (!pdwSupportedOptions || !pdwEnabledOptions)
        {
                return E_POINTER;
        }

        *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
        *pdwEnabledOptions = 0;

        if (NULL == pThis->GetInterface(&riid))
        {
                ;//                TRACE("Requested interface is not supported.n");
                return E_NOINTERFACE;
        }

        // What interface is being checked out anyhow?
        OLECHAR szGUID[39];
        int i = StringFromGUID2(riid, szGUID, 39);

        if (riid == IID_IDispatch)
        {
                // Client wants to know if object is safe for scripting
                *pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
                return S_OK;
        }
        else if (riid == IID_IPersistPropertyBag
                  || riid == IID_IPersistStreamInit
                  || riid == IID_IPersistStorage
                  || riid == IID_IPersistMemory)
        {
                // Those are the persistence interfaces COleControl derived controls support
                // as indicated in AFXCTL.H
                // Client wants to know if object is safe for initializing from persistent data
                *pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
                return S_OK;
        }
        else
        {
                // Find out what interface this is, and decide what options to enable
                ;//                TRACE("We didn't account for the safety of this interface, and it's one we support...n");
                return E_NOINTERFACE;
        }        
}

STDMETHODIMP CTestCtrl::XObjectSafety::SetInterfaceSafetyOptions(
                REFIID riid,
                DWORD dwOptionSetMask,
                DWORD dwEnabledOptions)
{
        METHOD_PROLOGUE_EX(CTestCtrl, ObjectSafety)

        OLECHAR szGUID[39];
        // What is this interface anyway?
        // We can do a quick lookup in the registry under HKEY_CLASSES_ROOTInterface
        int i = StringFromGUID2(riid, szGUID, 39);

        if (0 == dwOptionSetMask && 0 == dwEnabledOptions)
        {
                // the control certainly supports NO requests through the specified interface
                // so it's safe to return S_OK even if the interface isn't supported.
                return S_OK;
        }

        // Do we support the specified interface?
        if (NULL == pThis->GetInterface(&riid))
        {
                TRACE1("%s is not support.n", szGUID);
                return E_FAIL;
        }


        if (riid == IID_IDispatch)
        {
                ;//                TRACE("Client asking if it's safe to call through IDispatch.n");
                ;//                TRACE("In other words, is the control safe for scripting?n");
                if (INTERFACESAFE_FOR_UNTRUSTED_CALLER == dwOptionSetMask && INTERFACESAFE_FOR_UNTRUSTED_CALLER == dwEnabledOptions)
                {
                        return S_OK;
                }
                else
                {
                        return E_FAIL;
                }
        }
        else if (riid == IID_IPersistPropertyBag
                  || riid == IID_IPersistStreamInit
                  || riid == IID_IPersistStorage
                  || riid == IID_IPersistMemory)
        {
                ;//                TRACE("Client asking if it's safe to call through IPersist*.n");
                ;//                TRACE("In other words, is the control safe for initializing from persistent data?n");

                if (INTERFACESAFE_FOR_UNTRUSTED_DATA == dwOptionSetMask && INTERFACESAFE_FOR_UNTRUSTED_DATA == dwEnabledOptions)
                {
                        return NOERROR;
                }
                else
                {
                        return E_FAIL;
                }
        }
        else
        {
                TRACE1("We didn't account for the safety of %s, and it's one we support...n", szGUID);
                return E_FAIL;
        }
}

STDMETHODIMP_(ULONG) CTestCtrl::XObjectSafety::AddRef()
{
        METHOD_PROLOGUE_EX_(CTestCtrl, ObjectSafety)
        return (ULONG)pThis->ExternalAddRef();
}

STDMETHODIMP_(ULONG) CTestCtrl::XObjectSafety::Release()
{
        METHOD_PROLOGUE_EX_(CTestCtrl, ObjectSafety)
        return (ULONG)pThis->ExternalRelease();
}

STDMETHODIMP CTextCtrl::XObjectSafety::QueryInterface(
        REFIID iid, LPVOID* ppvObj)
{
        METHOD_PROLOGUE_EX_(CTestCtrl, ObjectSafety)
        return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}

출처 : 미친병아리