評価してください: 

開発者向け Active Template Library のセキュリティ更新プログラム

更新日: 2009 年 7 月 30 日


Active Template Library (ATL) は、コンポーネント オブジェクト モデル (COM) オブジェクトの開発が簡素化できるテンプレート ベースの C++ クラスのセットです。これらのオブジェクトは Windows および Web ソリューションで幅広く使用されています。そのため、これらのソリューションを展開している開発者にとって、その安全な使用と構築が重要な要件となります。

2009 年 7 月 29 日、マイクロソフトはセキュリティ アドバイザリ (973882) で ATL が影響を受けることをお知らせし、セキュリティ情報 MS09-035 の公開と共に、更新されたバージョンの ATL を提供しました。このセキュリティ情報では、ATL を使用して ActiveX コンポーネントを作成した開発者が影響を受ける可能性のある ATL の問題を解決します。さらにセキュリティ情報 MS09-034 は、影響を受ける ActiveX コントロールのリスク緩和に役立つ Internet Explorer の変更をサポートしています。

注意: Internet Explorer のセキュリティ情報では、この問題に対する新しい多層防御のオプションの詳細を提供し、この更新プログラムをインストールするように推奨しています。

マイクロソフトは Visual Studio 2003 およびそれ以降のバージョンの問題を解決する ATL ヘッダーおよびライブラリの更新プログラムを公開しました。開発者は セキュリティ情報から、更新プログラムをダウンロードできます。開発者が使用中の Visual Studio または Visual C++ のバージョンにより、問題の修正方法が異なります。

注意: Visual Studio 2002 およびそれ以前の製品は、サポートされていないため、マイクロソフトはメインストリームのサポート リリースへ移行することを推奨します。Visual Studio 2003 は延長サポートのため、こちらもメインストリームのサポート サービス対象製品への移行を推奨します。マイクロソフトの開発者ツールのサポートに関する詳細情報は サポート オンラインをご覧ください。

注意: Windows SDK には、この問題の影響を受けるソース コードのバージョンの ATL が含まれています。この更新プログラムを適用して、このガイダンスを実装するために ATL の Visual Studio のバージョンを使用してください。

SDK/DDK を Visual Studio ATL ヘッダーおよびライブラリと使用する方法についての疑問は、 Visual C++ フォーラムをご利用ください。


目次

  1. コントロールが影響を受けているかを判断する
  2. 影響を受けるコントロールを修正する
  3. 詳細なガイダンス
  4. 詳細情報

1. コントロールが影響を受けているかを判断する

コントロールのソース コードを再確認し、コントロールが影響を受けているかどうかを評価する必要があります。次は、コードの確認プロセスのためのステップ バイ ステップの手順です。

まず、最も影響を受ける COM コンポーネントは ActiveX コントロールであると思われますが、ここで強調しておきたいのは、必要条件が揃った場合、ATL の脆弱性は ATL を使用して作成されたすべての COM コンポーネントに当てはまるということです。

下の図では、影響を受けるコントロールを簡単に特定する方法を提供しています。

ATL Security Update 

 

ステップ 1: COM コンポーネントが ActiveX コントロールである場合、ActiveX コントロールが安全に初期化できる (SFI) かどうかを確認します

SFI の状態に関する詳細情報は、 Not safe = not dangerous? How to tell if ActiveX vulnerabilities are exploitable in Internet Explorer (英語) および MSDN: Safe Initialization and Scripting for ActiveX Controls (英語) をご覧ください。

ActiveX コントロールが SFI とマークされていない場合、IE から ActiveX コントロールへの攻撃経路はありません。

 

ステップ 2: コントロールが IPersistStreamInitImpl の継承または AtlIPersistStreamInit_Load (非常に低い可能性) を呼び出す場合、コントロールが影響を受けるプロパティ マップのマクロを使用しているかどうかについて確認します

PROP_ENTRY/ PROP_ENTRY_EX が使用されている場合、または PROP_ENTRY_TYPE/ PROP_ENTRY_TYPE_EX が VT_EMPTY、VT_DISPATCH または VT_UNKNOWN の種類と共に使用されている場合、コントロールが影響を受ける可能性があります。

例:

BEGIN_PROP_MAP(CMSWebDVD)

PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)

PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)

PROP_ENTRY("DisableAutoMouseProcessing", 70, CLSID_NULL) // vulnerable

PROP_ENTRY("BackColor", DISPID_BACKCOLOR, CLSID_StockColorPage)

PROP_ENTRY("EnableResetOnStop", 66, CLSID_NULL)

PROP_ENTRY("ColorKey", 58, CLSID_NULL)

PROP_ENTRY("WindowlessActivation", 69, CLSID_NULL)

PROP_ENTRY_TYPE("Param5", 5, CLSID_NULL, VT_DISPATCH) // vulnerable, VT_DISPATH used

PROP_ENTRY_TYPE("Param7", 7, CLSID_NULL, VT_UNKNOWN) // vulnerable, VT_UNKNOWN used

END_PROP_MAP()

 

ステップ 3: コントロールが CComVariant::ReadFromStream(pStream) を呼び出す場合、信頼できないデータが渡される可能性がないか確認します

信頼できないデータ と共に CComVariant::ReadFromStream(pStream) メソッドを使用することは安全ではありません。一方、CComVariant::ReadFromStream の呼び出しは、IPersistStreamInit の実装の一部になる場合が最も多く、これもまた、いずれの場合にも使用可能です。

ページのトップへ


2. 影響を受けるコントロールを修正する

サポートされていないバージョンの Visual Studio、Visual C++ および ATL はこの問題による影響を受ける可能性があります。サポートされていないバージョンを使用している場合、Visual Studio 2008 などのフル サポートされているバージョンの Visual Studio に移行する必要があります。しかし、Visual Studio 6.0、Visual C++ 6.0 またはそれ以前のバージョンを使用している場合、次を行うことによりこの脆弱性を解決できる場合があります。

  1. コントロールを再構築し、「初期化しても安全」とマークせずに提供しないよう、IPersistStreamInit および IPersistStorage のサポートを削除します。
  2. これらのインターフェイスのいずれか、または両方とも必要な場合、サポートされているバージョンの Visual Studio にアップグレードし、Visual Studio 2003 またはそれ以降について記載しているステップに従ってください。

マイクロソフトは、現在メインストリーム サポート中のバージョンの Visual Studio を使用することを推奨します。これにより、幅広いサポート オプションがご利用になれます。

 

ステップの概要

次のセクションでは、問題の解決方法の詳細を提供しますが、必要なステップの基本的な概要は次の通りです。

  1. コンポーネントを「初期化しても安全」とマークしている場合、「初期化しても安全」のマークを削除します。また、コントロールが IPersistStreamInitImpl を継承する場合、または AtlIPersistStreamInit_Load を呼び出す場合、プロパティ宣言で使用されている影響を受けるマクロ (PROP_ENTRY/ PROP_ENTRY_EX) を修正する必要があります。
  2. コントロールが CComVariant::ReadFromStream を呼び出す場合、ReadFromStream 呼び出しを更新し、vtExpected パラメーターを含むようにします。
  3. これらが該当する場合、次を行う必要があります。
    1. ATL ヘッダーおよびライブラリの更新プログラムを適用します。
    2. プロパティ マップを PROP_ENTRY ではなく PROP_ENTRY_TYPE (または _EX の実装) を使用するように変更します。vt 引数に VT_EMPTY を使用しないでください。VT_DISPATCH および VT_UNKNOWN は安全でないため、これらの使用は避けてください。
    3. VT_DISPATCH または VT_UNKNOWN のバリアント型を使用しなければならない場合、CLSID フィルタリングを実装する必要があります。
    4. CLSID フィルタリングが使用できない場合、ソリューションを再設計し、この依存性を削除する必要があります。これは、IPersistStreamInit および IPersistStorage が必要であるかどうか、またはクラスが本当に初期化しても安全であるかどうかを検討するいい機会となります。
  4. DLL バージョンの ATL (ATLxx.DLL) の CLSID フィルタリング。プロジェクトが ATL.DLL (ATLxx.DLL) を使用する場合、コードを再設計して上記のように CLSID フィルタリングの必要条件を削除するか、または _ATL_DLL の定義を削除することにより、DLL バージョンの ATLxx.DLL から切り替える必要があります。

ページのトップへ


3. 詳細なガイダンス

 

ステップ 1: 更新プログラムを適用します

マイクロソフトは、これらの問題を解決する ATL ヘッダーおよびライブラリの更新プログラムを公開しました。開発者は、 こちらのセキュリティ情報から更新プログラムをダウンロードしてください。

 

ステップ 2: サポートされているインターフェイスをチェックします

ほとんどの場合、コントロールについての実際の開発者の必要条件は、SFI コントロールを HTML で PARAM によりインスタンス化することです。たとえば、下記の HTML はインスタンス化されているコントロールの 2 つの例です。

<object id="X" classid="CLSID:<Your CLSID>" >

  <param name="FOO" value="FOO">

</object>

<object classid=”CLSID:<Your CLSID>” data="stream.bin" </object>

この場合には、IPersistPropertyBag または IPersistPropertyBag2 をサポートする必要があります。IPersistStreamInit、IPersistStream または IPersistStorage のサポートは必要なく、実際には望ましくありません。これらのインターフェイスのサポートを削除することを検討してください。

:  コントロールが IPersistStorageImpl を使用して IPersisteStorage インターフェイスを実装している場合、IPersistStreamInit の実装を削除した後、機能しなくなります。

 

ステップ 3: コントロールのコードに影響を受けるマクロが存在する場合、それらを修正します

コントロールが IPersistStreamInitImpl (すなわち IPersistStreamInit のサポート) から継承する必要がある場合、または AtlIPersistStreamInit_Load を呼び出す必要がある場合、プロパティ宣言で使用される影響を受けるマクロを修正する必要があります。影響を受ける古いマクロ PROP_ENTRY/ PROP_ENTRY_EX は推奨されていないため、安全なマクロ PROP_ENTRY_TYPE & PROP_ENTRY_TYPE_EX と交換する必要があります。

古いマクロ:

#define PROP_ENTRY      (szDesc, dispid, clsid)

#define PROP_ENTRY_EX   (szDesc, dispid, clsid, iidDispatch)

新しいマクロ:

#define PROP_ENTRY_TYPE       (szDesc, dispid, clsid, vt)

#define PROP_ENTRY_TYPE_EX    (szDesc, dispid, clsid, iidDispatch, vt)

上記に示しているように、新しいマクロ (PROP_ENTRY_TYPE/ PROP_ENTRY_TYPE_EX) により、予期された種類が提供されます。たとえば、VT_BSTR が予期されており、VT_UNKNOWN がストリームから読み取られると、呼び出しが失敗します。クラスを初期化しても安全な PROP_ENTRY_TYPE/ PROP_ENTRY_TYPE_EX を使用しないでください。これでは予期されている種類がないという意味になり、どのような種類でも (安全なものでも、または安全でないものでも) ストリームから読み取られる可能性があるためです。

マクロ PROP_ENTRY_TYPE および PROP_ENTRY_TYPE_EX は、VT_UNKNOWN または VT_DISPATCH が予期されている種類である場合を除き、安全に使用できます。コントロールがこれらの種類をサポートする必要がある場合、マイクロソフトはこれを注意深く検討し、これに対する有効なユーザーのシナリオがあることを確認し、そのシナリオで必要ない場合、このサポートを削除することを推奨します。さらに、これらのシナリオで、コントロールを SFI とマークする必要性を検討し、必要でなければそのマークを削除してください。

SFI コントロールが VT_DISPATCH または VT_UNKNOWN を適切にサポートする必要がない場合、この CLSID フィルタリングの ATL の更新プログラムが提供する次の新しいマクロの使用を検討できる場合があります。

: ATL (ATLxx.DLL) の DLL バージョンでの CLSID フィルタリング。プロジェクトが ATL.DLL (ATLxx.DLL) を使用する場合、コードを再設計し、上記の CLSID フィルタリングの必要条件を削除するか、_ATL_DLL の定義を削除することにより、DLL バージョンの ATLxx.DLL から切り替える必要があります。

これらのマクロは、その名前がすべて PROP_ENTRY_INTERFACE で始まっており、これらのマクロにより、呼び出し元が予期される VT_ の種類だけでなく、ストリームから読み取ることのできる有効な CLSID もまた特定することができます。ストリームから読み取られる CLSID がマクロにより提供されるものと一致しない場合、呼び出しは失敗します。

#define PROP_ENTRY_INTERFACE(szDesc, dispid, clsid, rgclsidAllowed, cclsidAllowed, vt)

#define PROP_ENTRY_INTERFACE_CALLBACK(szDesc, dispid, clsid, pfnFunc, vt)

#define PROP_ENTRY_INTERFACE_EX(szDesc, dispid, clsid, iidDispatch, rgclsidAllowed, cclsidAllowed, vt)

#define PROP_ENTRY_INTERFACE_CALLBACK_EX(szDesc, dispid, clsid, iidDispatch, pfnFunc, vt)

上記のマクロに関するその他の注意:

  • vt: 要求された情報を含むバリアント型 (Exptected varint type)
  • rgclsidAllowed: 許可された CLSID リスト、rgclsidAllowed はフォームの配列

const CLSID rgclsidAllowed[] =

{

   CLSID_Foo,

   CLSID_Bar,

};

  • pfnFunc: HRESULT を返し、渡された CLSID を許可するかどうかを示す関数ポインターです。この基本的な機能は、特定の CLSID の読み込みが許可されるかどうかを識別することです。コールバック関数の実装は許可されない CLSID に E_ACCESSDENIED、許可される CLSID に S_OK を返すことです。失敗した HRESULT が許可しないを示し、成功した HRESULT が許可するを示すのであれば、操作中に発生したその他のエラーが返される可能性があります。
  • cclsidAllowed: 許可された CLSID 数

次にこれらの新しいマクロを使用する方法に関する例を示します。ここでも、クラスが本当に VT_DISPATCH または VT_UNKNOWN プロパティを持つ必要があるかどうかを注意深く検討してください。

PROP_ENTRY_INTERFACE("PROP_ENTRY_INTERFACE", 0, CLSID_PropPage, &CLSID_Allowed, 1, VT_DISPATCH)           

PROP_ENTRY_INTERFACE_EX("PROP_ENTRY_INTERFACE_EX", 0, CLSID_PropPage, __uuidof(IAlternate), &CLSID_Allowed, 1, VT_DISPATCH)

PROP_ENTRY_INTERFACE_CALLBACK("PROP_ENTRY_INTERFACE_CALLBACK", 0, CLSID_PropPage, AllowedCLSID, VT_DISPATCH)   

PROP_ENTRY_INTERFACE_CALLBACK_EX("PROP_ENTRY_INTERFACE_EX", 0, CLSID_PropPage, __uuidof(IAlternate), AllowedCLSID, VT_DISPATCH)     

HRESULT AllowedCLSID(const CLSID& clsid, REFIID iidInterface, void** ppvObj);

: ppvObj パラメーターはオプションです。コールバック関数がその操作の一部としてクラスをインスタンス化する必要がある場合、iidInterface により提供されたインターフェイスにポインターを返すか、または *ppvObj = NULL を設定します。*ppvObj がコールバックにより設定されない場合、ATL はクラス自体をインスタンス化します。オブジェクトで使用が安全であることを確認する (すなわち、IObjectSafety インターフェイスを呼び出すことにより、オブジェクトがインスタンス化に安全であるかどうかをチェックする) ための追加チェックが必要な場合もあります。このような場合、安全の設定が使用されるように、コールバックで作成されたインスタンスは ATL に返される必要があります。この機能により、開発者は読み込まれたインターフェイスをよりよく制御することができます。

要約すると、次のようになります。

  1. 影響を受ける各マクロについて、そのプロパティに使用されるバリアント型を識別します。
  2. 要求された情報を含むバリアント型が VT_DISPATCH ではなく、また VT_UNKNOWN でない場合、要求された情報を含むバリアント型 (vt) を指定する安全なマクロ PROP_ENTRY_TYPE または PROP_ENTRY_TYPE_EX を使用することにより、コードを更新します。
  3. 要求された情報を含むバリアント型が VT_DISPATCH または VT_UNKNOWN である場合、許可された CLSID の配列か、このチェックを実行するコールバック関数を指定する PROP_ENTRY_INTERFACE または PROP_ENTRY_INTERFACE_EX を使用します。

 

ステップ 4: CComVariant::ReadFromStream を使用するコントロールについて、ReadFromStream(pStream) への呼び出しを修正します

コントロールが信頼されていないデータを渡して CComVariant::ReadFromStream を呼び出す場合、ReadFromStream(pStream) から ReadFromStream(pStream, vtExpected) に呼び出しを更新する必要があります。ReadFromStream(pStream, vtExpected) では vtExpected が読み取られる値の要求された情報を含むバリアント型です。

たとえば、

旧:

hr = var.ReadFromStream(pStm);

修正:

hr = var.ReadFromStream(pStm, vtExpected);

コントロールがバリアント型 VT_DISPATCH または VT_UNKNOWN を持つ場合、呼び出しを ReadFromStream(pStream) から ReadFromStream(pStream, vt, rgclsidAllowed, cclsidAllowed) に更新します。

ReadFromStream(pStream, vt, rgclsidAllowed, cclsidAllowed) では、次のとおりです。

  • vt:  要求された情報を含むバリアント型
  • rgclsidAllowed: 許可された CSLID リストまたは関数ポインター
  • cclsidAllowed: 許可された CLSID 数

例:

const CLSID rgclsidAllowed[] =

{

}

ClassesAllowedInStream allowed = { rgclsidAllowed };

hr = var.ReadFromStream(pStm, VT_UNKNOWN, allowed, _countof(rgclsidAllowed));

または

HRESULT HrAllowClsid(const CLSID& clsid, REFIID iidInterface, void **ppvObj);       

ClassesAllowedInStream allowed = { (const CLSID *) & HrAllowClsid };

hr = var.ReadFromStream(pStm, VT_UNKNOWN, allowed, 1));

ここでも、VT_DISPATCH および VT_UNKNOWN を注意深く扱ってください。

ページのトップへ


4. 詳細情報

: この更新プログラムを Windows Server 2003 にインストールするためには、最初に KB925336 または KB973825 で説明している更新プログラムをインストールする必要がある場合もあります。

: Visual Studio および Windows の両方とも、ATL.DLL を同梱しています。ATL.DLL および ATLXX.DLL (XX はインストールされている Visual Studio のバージョンに関連しています) の両方とも正しく更新されていることを確認する必要があります。

ページのトップへ