Академический Документы
Профессиональный Документы
Культура Документы
A Safe-for-Scripting Template
Version 1.15
Microsoft Corporation
January 2009
Abstract
The default security model for “safe-for-scripting” or “safe-for-initialization” ActiveX
controls is for the control to always or never be safe. A control that is “always safe” can
be used by any web page author with any script. This template allows an ActiveX
developer to easily restrict a control so that it is only “safe” in a preselected list of
domains, thus limiting the ability of malicious web page authors from repurposing the
control.
This same template can also be used to make a control that is always safe, but has
different behaviors depending on which domain it is running on. Consolidating the
domain checking into a single, shared library makes it easier to fix if a problem is found.
Microsoft, MS-DOS, Windows, Windows Media, Windows NT, Windows Server, Windows Vista,
Active Directory, ActiveSync, ActiveX, Direct3D, DirectDraw, DirectInput, DirectMusic, DirectPlay,
DirectShow, DirectSound, DirectX, Expression, FrontPage, HighMAT, Internet Explorer, JScript,
Microsoft Press, MSN, NetShow, Outlook, PlaysForSure logo, PowerPoint, SideShow, Visual Basic,
Visual C++, Visual InterDev, Visual J++, Visual Studio, WebTV, Win32, and Win32s are either
registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other
countries.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Background
ActiveX controls can be hosted by scripting environments and driven by script. In some
hosts, such as Internet Explorer, the script can come from an unknown, untrusted
source. Because of this, a security model was created to ask the control (through the
IObjectSafety interface) “Is it okay for you to initialize and interact with script in an
untrusted environment?” If yes, the control is marked “safe-for-initialization” or “safe-for-
scripting,” respectively.
Even if the control is signed, any malicious user can host the control on a Web site. You
would trust a control signed by Microsoft®, right? Unfortunately, the original control
author (the one the user sees a certificate for) is ultimately responsible for any misuse.
The SiteLock template makes it very easy for a control written in ATL to determine
where the control is being hosted and to decide if it is “safe” or not based on the domain
of the hosting Web page. If the domain is not in a pre-selected list of “safe” domain
names or zones, the control declares itself unsafe on that page.
See “Designing Secure ActiveX Controls” on MSDN and Hunting Security Bugs, chapter 18 for
more information about “safe-for-scripting” and “safe-for-initialization.”
Historical Examples
Here are two Microsoft Security Bulletins from the past that help demonstrate this point.
MS00-034: Office 2000 UA Control Vulnerability: Microsoft Office Help implemented the
“Show Me” feature of online help with a control that allowed the help process to walk a
user through a set of tasks described in a help article. However, since this control was
marked as safe, any Web site could use this control to “walk” a user through a set of
actions whether the user wanted to do it or not.
MS01-038: Outlook View Control Exposes Unsafe Functionality: Microsoft Outlook had
an ActiveX control that allowed you to view your mail (for Outlook-on-the-Web
scenarios). There were methods on that control that allowed it to delete messages in
your Inbox. Using this control, any Web page author anywhere could delete your e-mail
by convincing you to browse to a Web page controlled by the attacker.
The Solution
The SiteLock template replaces the standard ATL template with its own implementation
of IObjectSafety, called IObjectSafetySiteLockImpl. It automatically queries the host
for the URL of the Web page that is hosting the control, extracts the protocol scheme
and fully qualified domain name from that URL, and compares it to a list created by the
control developer at build time to see if the site should be trusted.
The URL is parsed with the UrlGetPart function (the same function used internally by
CoInternetParseUrl) to avoid getting tricked by non-standard URLs. Developers who
have tried to implement this domain-checking in the past usually get it wrong because
they don't realize how “tricky” URLs can be.
Answer: none of them. However, a simple string comparison of the URL could easily be
fooled by all but the last of these addresses. A control that checks for an intranet URL
might also be fooled by the last example into thinking it was on an intranet, when in
reality it was on the Internet. (The last address belongs to Yahoo!)
In addition to limited use by domain, most controls have a limited “lifespan.” Once the
control’s useful lifespan has elapsed, it will probably be of little or no value—except
perhaps to malicious users should a security problem be found. Therefore, SiteLock also
includes an optional mechanism to automatically “expire” the control after a certain date.
When that time has passed, the control becomes unsafe. If it turns out that you still need
to use the control after it has expired, you can rebuild the control with a new expiration
date and update your Web site.
By automatically expiring controls in this way, you can prevent a potential security
problem that is created by a control that has outlived its usefulness. When in doubt, pick
a shorter expiration period rather than a longer one, as it is easier to re-release a control
with a new expiration date than it is to deal with vulnerabilities in an obsolete control that
hasn't expired yet.
A Word of Caution
SiteLock helps prevent malicious users from hosting your control on their own Web sites
or sending the control in an HTML e-mail message. However, if your Web site is
vulnerable to script injection or cross-site scripting, an attacker could still cause
malicious script to execute in the context of your site. Such script could freely call the
site-locked control with arbitrary parameters.
Therefore, to ensure the safe operation of your site-locked control, you should also
ensure that your Web site is protected. As a precautionary measure, your control should
explicitly prompt the user for permission before taking any potentially dangerous action.
Implementation Guide
To integrate SiteLock into your ActiveX control written in ATL, use the following step-by-
step guide.
1. Include the SiteLock header file after the core ATL headers.
#include <sitelock.h>
In the declaration of your object’s class, add the following to the list of base
classes for your class.
public IObjectSafetySiteLockImpl<CYourClass, INTERFACESAFE_FOR_...>
This template replaces the declaration of IObjectSafetyImpl that you may have
ATL generates a COM_MAP in the header file for your class to indicate which
interfaces your control supports. Add the following to your map:
COM_INTERFACE_ENTRY(IObjectSafety)
COM_INTERFACE_ENTRY(IObjectSafetySiteLock)
This member must either be public in your class, or it must be made a friend of
IObjectSafetySiteLockImpl. If you do not want your control to expire, you can
instead define SITELOCK_NO_EXPIRY before you include the SiteLock header
file.
This template needs to know where the control is being hosted. There are two
ways of doing this. The IObjectWithSite interface is a lightweight way to get the
IUnknown of your host container and is strongly recommended.
To use IObjectWithSite, add the following to the list of base classes in your class
declaration:
public IObjectWithSiteImpl<CYourObject>
Then, add the following to the COM_MAP section in your header file:
COM_INTERFACE_ENTRY(IObjectWithSite)
IOleObject allows a control to have many more OLE interactions with its
container (including things like application embedding). Most controls don’t need
this level of support. If you choose to use IOleObject, then you must add the
following before you include the SiteLock header file:
#define SITELOCK_USE_IOLEOBJECT
Note You cannot implement both IOleObject and IObjectWithSite in the same
control. If you do, Internet Explorer will only use IOleObject and ignore your
implementation of IObjectWithSite.
7. Link with urlmon.lib The APIs that SiteLock uses to do the domain checking reside in
urlmon.lib.
SiteLock, starting with version 1.15, includes SAL annotations. If your build
environment is incompatible or you use an alternate annotation strategy, define
SITELOCK_USE_ALTERNATE_SAL_ANNOTATIONS and optionally provide a
mapping by using the sample macros located near the beginning of sitelock.h.
8. Include the SiteLock header file after the core ATL headers.
#include <sitelock.h>
9. Derive from CSiteLock.
In the declaration of your object’s class, add the following base class:
public CSiteLock<CYourClass>
Note that this is not a COM interface, but just a class adding internal
implementation features.
10. Derive from IObjectWithSite or IOleObject.
You may choose any name you want. For more information, refer to the
previous section.
12. Call one of the following functions to perform security checks.
bool InApprovedDomain(const SiteList* rgslTrustedSites, int
cTrustedSites);
The iAllowType member indicates the action taken when this array entry is matched.
Allow means that this describes a domain that a control can run in. Deny means that this
describes a domain that is explicitly denied being safe. For both of these records,
szScheme is the type of URL that this record describes (like “http” or “https”) and
szDomain is the domain suffix for this record.
Note To allow both http and https, you must create an entry for each.
The record is considered a match if the domain matches the domain of the URL exactly,
or if the URL is a sub-domain of an exact match. For example:
microsoft.com
microsoft.com matches office.microsoft.com
mymicrosoft.com
does not match www.microsoft.com.hacker.com
If the domain begins with “=” only the specified domain matches.
microsoft.com
=microsoft.com matches
www.microsoft.com
does not match
The wildcard character (“*”) matches all domains and can be used to create a generic
allow rule for a specific protocol scheme. You do not need to create a generic deny rule,
as all domains are disallowed by default.
When constructing a trusted sites list, consider whether your control might be accessed
from a URL without a leading www, as "example.com" instead of "www.example.com." If
matching any subdomain of your site is acceptable (often the desired behavior),
"example.com" by itself will do. However, to include only "example.com" by itself, create
a separate rule using an equal sign, as follows:
It is also considered a match if the domain is NULL and UrlGetPart returns an error while
fetching the domain. This is useful for schemes (such as outlook://) that do not include a
domain name as part of the URL.
Case Matters
The domain is an exact check. Before comparison, UrlGetPart converts the domain
name into a “canonical” or normal form, which includes converting the URL to lower
case. The template also converts URLs that contain Unicode characters into Punycode
(see RFC 3492). Whether normalization converts strings to lower-case depends on the
scheme provider.
If you are ever in doubt, you can use icu.exe to normalize and parse the components of
the URL, and display the scheme, domain name, and security zone. This simple
command line utility is included in the SiteLock installation folder.
Order Is Important
All entries in the site list are checked sequentially. The first matching record is the one
whose result is returned. For example, if you define the following site list:
const CYourObject::SiteList CYourObject::rgslTrustedSites[] =
{{ SiteList::Deny, L"http", L"users.microsoft.com" },
{ SiteList::Allow, L"http", L"microsoft.com" },
{ SiteList::Allow, L"http", SITELOCK_INTRANET_ZONE },
};
With the above list, Fred (at “fred.users.microsoft.com”) would not be able to host the
control because he would be denied by the first rule, even though the second rule would
normally allow him. On the other hand, “services.microsoft.com” could host the control,
as well as any system on the local intranet (see “Zone Entries” later).
Now “fred.users.microsoft.com” can host the control because the first rule allows it (as
he is a subhost of the microsoft.com domain). The second rule is not processed.
Zone Entries
SITELOCK_TRUSTED_ZONE Allow any host in the Trusted zone to host this control.
IObjectSafetySiteLock has its own interface RIID that you can query by using
uuidof(IObjectSafetySiteLock) after including the header file. Expressing the
value in this way protects you against changes to the RIID that are mandated by non-
backwards-compatible updates to the template.
GetCapabilites
HRESULT GetCapabilities(DWORD *pdwCapability);
The pdwCapability in/out parameter specifies the capabilities you are querying the
interface for. On return, it contains the requested information. The API returns S_OK for
capabilities it supports and E_NOTIMPL if it is unaware of the requested capabilities.
The pSiteList parameter receives a pointer to the array of site list entries, and cSites
receives a count of the number of entries. Automation tools can use this interface to
verify quickly that the list was set up correctly.
GetExpiryDate
HRESULT GetExpiryDate(DWORD *pdwLifespan, FILETIME *pExpiryDate);
[1.05] The pdwLifespan parameter receives the lifespan of the control measured in days
from the time the control was built, as specified by the developer when the control was
authored, and pExpiryDate receives the computed moment of expiration in GMT, in
Microsoft Windows® FILETIME format.
References
Designing Secure ActiveX Controls
(http://go.microsoft.com/fwlink?LinkId=96500) provides an overview of the ActiveX
security model and what it means for a control to be safe.