About IObject Safety Extensions for Internet Explorer

This document describes the extensions to the IObjectSafety interface that support the new security features implemented in Microsoft Internet Explorer 4.0. It covers the following topics.

  • Introduction
  • IObjectSafety Interface
  • Security Manager
    • New Security Bits
  • Object Creation
  • Related topics

Introduction

The IObjectSafety interface should be implemented by objects that have interfaces which support untrusted clients, for example, scripts. This allows the owner of the object to specify which interfaces need to be protected from possible untrusted use.

IObjectSafety Interface

The IObjectSafety interface allows a container to ask a control to make itself safe, or to retrieve the current initialization or scripting capabilities for the control. This interface is defined in the Objsafe.h file. Currently two capabilities are supported: safe for scripting and safe for initialization. These capabilities correspond to the following bit flags, which are defined in Objsafe.h.

INTERFACESAFE_FOR_UNTRUSTED_DATA Specifies that the interface is safe for initialization.
INTERFACESAFE_FOR_UNTRUSTED_CALLER Specifies that the interface is safe for scripting.

 

Script engines must support the extensions in order to run under Internet Explorer 4.0. Controls need to implement these extensions only if they want to fully support Internet Explorer's security model.

Security Manager

When the INTERFACE_USES_SECURITY_MANAGER bit is enabled on an object, the object must use the security manager provided by Internet Explorer 4.0 to make security decisions. Currently, the only scenario where the security manager needs to be queried is when objects are created.

New Security Bits

The following new bits for IObjectSafety are defined in objsafe.idl. These bits provide the mechanism to specify the access security for a given object.

INTERFACE_USES_DISPEX Specifies that the object uses the IDispatchEx interface.
INTERFACE_USES_SECURITY_MANAGER Specifies that the object uses the IInternetHostSecurityManager interface.

 

These bits apply to entire objects and as a result, when interpreting these bits, implementations of IObjectSafety should ignore the REFIIDparameter passed into IObjectSafety::GetInterfaceSafetyOptions and IObjectSafety::SetInterfaceSafetyOptions. When the INTERFACE_USES_DISPEX bit is enabled on an object, the object must use IDispatchEx::InvokeEx rather than IDispatch::Invoke to access any objects which support IDispatchEx. The only exception to this rule is that IDispatch::Invoke may be used to retrieve the default value of an object (DISPID_VALUE). IDispatchEx::InvokeEx includes a parameter so that a callee may request services from a caller. Objects implemented in Internet Explorer 4.0 use this to query for the security manager service that provides caller context information required to ensure security.

For more information about identifying a control as safe for scripting using IObjectSafety, see Safe Initialization and Scripting for ActiveX Controls.

Object Creation

The following code sample illustrates the object creation algorithm.

HRESULT CreateObject(IInternetHostSecurityManager *psecman, 
    DWORD dwSafetyEnabled, BOOL fWillLoad,
    CLSID clsid, REFIID riid, void **ppv);
{
    HRESULT hr;
    if (dwSafetyEnabled & INTERFACE_USES_SECURITY_MANAGER)
    {
        // Ask security manager if we can create objects.
        DWORD dwPolicy;
        if (FAILED(hr = psecman->ProcessUrlAction(
             URLACTION_ACTIVEX_RUN, (BYTE *)&dwPolicy, sizeof(dwPolicy), 
             (BYTE *)&clsid, sizeof(clsid), 0, 0)))
        {
            return hr;
        }
    
        if (URLPOLICY_ALLOW != dwPolicy)
            return E_FAIL;
    }

    if (FAILED(hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER, riid, ppv)))
        return hr;

    // Must go to CLEANUP after this point on failure to free *ppv.
    
    if (dwSafetyEnabled & INTERFACE_USES_SECURITY_MANAGER)
    {
        // Query the security manager to see if this object is safe to use.
        DWORD dwPolicy, *pdwPolicy, cbPolicy;
        
        CONFIRMSAFETY csafe;
        csafe.punk = *(IUnknown **)ppv;
        safe.clsid = clsid;
        csafe.dwFlags = (fWillLoad ? CONFIRMSAFETYACTION_LOADOBJECT : 0);
        
        if (FAILED(hr = psecman->QueryCustomPolicy(
            GUID_CUSTOM_CONFIRMOBJECTSAFETY, (BYTE **)&pdwPolicy, 
            &cbPolicy, (BYTE *)&csafe, sizeof(csafe), 0)))
        {
            goto CLEANUP;
        }

        dwPolicy = URLPOLICY_DISALLOW;
        if (NULL != pdwPolicy)
        {
            if (sizeof(DWORD) <= cbPolicy)
                dwPolicy = *cbPolicy;
            CoTaskMemFree(pdwPolicy);
        }
    
        if (URLPOLICY_ALLOW != dwPolicy)
        {
            hr = E_FAIL;
            goto CLEANUP;
        }
    }
    else if (dwSafetyEnabled & (INTERFACESAFE_FOR_UNTRUSTED_DATA |
                    INTERFACESAFE_FOR_UNTRUSTED_CALLER))
    {
        // Perform old safety checks.
    
    }

    return NOERROR;

CLEANUP:
    (*(IUNKNOWN **)ppv)->Release();
    return hr;
}

The flag fWillLoad should be set if the object that is created will be initialized using an IPersist* interface. An object can get the security manager by querying its site for the SID_SInternetHostSecurityManager service. For controls, the site is set up using IOleObject::SetClientSite. For other objects, the site is set up using IObjectWithSite::SetSite. Objects that create other objects using the code above should implement a service provider and set up client sites for any objects that are created.

Conceptual

Designing Secure ActiveX Controls

Safe Initialization and Scripting for ActiveX Controls