보안문제 해결하기
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);
}
출처 : 미친병아리
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);
}
출처 : 미친병아리