Windows PowerShell署名をお願いします

Don Jones

2008 年 1 月号の Windows PowerShell コラムでは、Windows PowerShell スクリプトにデジタル署名することの重要性を強調しました。また、AllSigned 以外の実行ポリシーを使用することによって、環境内のセキュリティの脆弱性が大幅に高まる可能性のあるいくつかのシナリオについて説明しました。

このときは、実際にスクリプトに署名する方法については、詳しい説明を省略しました。このコラムの内容を確認するには、technetmagazine.com/issues/2008/01/PowerShell を参照してください。では、今月のコラムのテーマはどうしましょうか。

単なる署名ではありません

署名という語は、これから説明するテーマを表す正しい専門用語ですが、その語自体は、実際の処理を適切に表していません。スクリプトに署名するということは、契約を結ぶときやクレジット カードを使用するときのように、それを承認または許可するということではありません。デジタル セキュリティにおける署名とは、署名者の ID を付加することによって、あるものの状態が変更されていないことを保証する処理です。この処理は、すべて暗号化に基づいて行われます。暗号化では、(少なくともこの場合) 2 つの暗号化キーが使用されます。

これらのキーは、互いに異なることから、"非対称キー" と呼ばれます。非対称キーは、暗号化を行った人物のみがアクセスできる秘密キーと、だれでもアクセスできる公開キーで構成されます。少し説明を簡略化しますが、基本的に、秘密キーで暗号化されたデータは、対応する公開キーを使用しなければ暗号化を解除できません。

ここから、そのしくみについて説明します。繰り返しますが、ここでは説明を円滑に進めるために、内容を少し簡略化しています。まず、署名する Windows PowerShell® スクリプトと、スクリプトへの署名に使用する秘密キーが含まれた証明書を用意します。Windows PowerShell 自体にも、指定されたスクリプトと証明書を使用して実際に署名を実行するコマンドレット (この後すぐ説明します) が含まれています。このコマンドレットを実行すると、Windows PowerShell は秘密キーを使用して、指定されたスクリプトを暗号化します。暗号化されたコピーは、スクリプトの最後に一連のコメントとして追加され、よく意味のわからないテキストとして表示されます (図 1 参照)。署名者の ID もそれらのコメント内にエンコードされますが、暗号化はされません。ID 自体は、暗号化機能を使用しなくても確認できます。

Figure 1 スクリプトの最後に格納された署名ブロック

Figure 1** スクリプトの最後に格納された署名ブロック **(画像を拡大するには、ここをクリックします)

後から署名を調べるときに、Windows PowerShell は ID をデコードし、それを使用して公開キーを取得します。署名の残りの暗号化を解除できるのは署名者の公開キーのみであるため、Windows PowerShell は、署名の暗号化を解除できた場合、公開キーの作成者が署名を実行したことを認識します。他のユーザーが署名を実行した場合、この署名者の公開キーで署名の暗号化を解除することはできません。署名の暗号化が解除されたら、Windows PowerShell は、スクリプトと、署名に暗号化されたそのスクリプトのコピーを比較します。それらが一致した場合、署名は変更されていないものと見なされます。2 つのスクリプトが異なる場合、署名は破損しており、無効であると見なされます。

このようにしてクリア テキストのスクリプトを署名で保護し、気付かないうちに変更されることがないようにします。スクリプト自体は簡単に変更できますが、変更されたスクリプトと一致するように署名を変更するには、必ず署名者の秘密キーを使用する必要があります。そして、その秘密キーを所持するのは署名者のみです。

確かにここでは、前提となる技術的な処理の説明を簡略化しています。実際には、署名者の公開キーのコピー、キーを発行した証明機関 (CA) に関する情報など、より多くの情報が署名に含まれます。しかし、ここでは署名処理における重要な部分の説明は省略していません。また、署名を使用することによって実際に不正な変更からスクリプトを保護できるということも明確にしています。

セキュリティを確保するには、秘密キーを厳重に保護することが重要です。秘密キーは、他のユーザーの手に渡らないようにする必要があります。Windows にキーをインストールするときは、気付かないうちに悪意のある処理によって使用されないよう、直ちにそのキーをパスワードで保護する必要があります。スマート カードを使用すると、スマート カードに秘密キーを格納できるので、セキュリティを強化できます。スマート カードでは、秘密キーがカードから切り離されることはありません。暗号化されるデータは、スマート カード リーダー ハードウェアからカードに転送された後、カードの回路によって暗号化され、その結果がコンピュータに返されます。

証明書を取得する

今月のコマンドレット : Export-CSV

PowerShellCommunity.org のフォーラムでよく尋ねられるのは、Windows PowerShell で Microsoft Excel® へのエクスポートを実行できるかどうかということです。もちろんそれは可能です。Excel はネイティブで CSV ファイルを開き、編集および保存することができるので、Export-CSV コマンドレットを使用すると、Excel へのエクスポートを実行できます。たとえば、サービスの一覧をエクスポートする場合は、Get-Service | Export-CSV MyServices.csv を実行すれば、作業は完了です。また、Export-CSV を任意のパイプラインの末尾に追加し、そのパイプライン内のすべてのオブジェクトを指定した CSV ファイルにエクスポートすることもできます。既定では、Export-CSV は、ヘッダー行をファイルの先頭に追加し、その行を使用して、エクスポートされたオブジェクトの種類を指定します。Excel がファイルを開く操作を妨げないように、この行はコメントになっています。オブジェクトの種類に関する情報をエクスポートしない場合は、単純に -notype パラメータを Export-CSV に追加します。また、-force パラメータを追加して、同じ名前の既存の CSV ファイルを確認なしで上書きしたり (既定では確認メッセージが表示されます)、-noClobber パラメータを追加して、その名前のとおり、既存のファイルを上書きしないようにすることもできます。

スクリプトに署名するには、特定の種類の証明書 (クラス 3 の Authenticode コード署名証明書) が必要です。この証明書を入手する主な方法は 3 つあります。1 つ目は、組織内の公開キー基盤 (PKI) を使用する方法です (組織に実装されている場合)。適切に実装された PKI では、ルート CA が組織のすべてのコンピュータによって信頼されています。CA から発行された証明書を組織内で使用するには、この要件を満たしている必要があります。

Windows® 2000 以降、Windows Server® には独自の証明書サーバー ソフトウェアが付属しており、そのソフトウェアを使用して独自の PKI を作成できます。PKI を完全に実装するには、非常に多くの計画作業を行う必要がありますが、コード署名証明書を発行するためだけに PKI を使用する場合、すべての作業を行う必要はありません。単純にグループ ポリシーを使用して、CA のルート証明書をコンピュータにインストールすれば、すべてのコンピュータでその証明書が信頼されます。

2 つ目は、商用の CA を使用する方法です。商用の CA を使用する利点の 1 つは、いずれかの主要な CA を使用したときに、組織のコンピュータが既にその CA の証明書を信頼するように構成されている可能性が高いことです (Windows XP では既定で多くの証明書が信頼されていますが、Windows Vista® ではその数が大幅に減少していることに注意してください)。よく使用される商用の CA としては、VeriSign (verisign.com) が挙げられます。その他、CyberTrust (cybertrust.com) や Thawte (thawte.com) なども調べてみる価値はあります。

コード署名証明書を入手する 3 つ目の方法は、Makecert.exe などのツールを使用して独自の自己署名証明書を作成することです。このツールは Windows Platform SDK に付属しており、一部のエディションの Microsoft® Office でもインストールされます。これらの他にも、さまざまな方法でこのツールを入手できます。自己署名証明書の利点は、無償であること、およびインフラストラクチャを必要としないことです。一方、自己署名証明書の欠点は、自分のコンピュータでしか使用できないことです。しかし、(コード署名を使用したテストや一般的な実験を行う場合など) 自分のコンピュータのみでスクリプトを実行する必要がある場合は、Makecert.exe が役立ちます。このツールに関するドキュメントは、go.microsoft.com/fwlink/?LinkId=108538 で参照できます。このツールは、これまでに多くのバージョンが公開されているので、使用中のコンピュータで古いバージョンを実行している場合は、ドキュメントの説明どおりに動作しないことがあります。

Makecert.exe を入手したら、Windows PowerShell コマンド ラインで次のようなコードを実行して、自己署名証明書を作成できます (このコラムを読んでいるのであれば、cmd.exe ではなく Windows PowerShell を使用してください)。

makecert -n "CN=MyRoot" -a sha1 –eku
1.3.6.1.5.5.7.3.3 -r -sv root.pvk root.cer 
–ss Root -sr localMachine

続いて、次のコードを実行します。

makecert -pe -n "CN=MyCertificate" -ss MY 
–a sh1 -eku 1.3.6.1.5.5.7.3.3 -iv root.pvk 
–c root.cer

Makecert.exe によって、キーを保護するためのパスワードが要求された後、証明書が作成されます。この証明書がインストールされたことを確認するには、Windows PowerShell で次のコードを実行します。

gci cert:\CurrentUser\My -codesigning

これにより、CERT: ドライブ (Windows 証明書ストア) に格納されているすべてのコード署名証明書が一覧表示されます。ちなみに、これらの情報はすべて Windows PowerShell でも確認できます。この情報を確認するには、Get-Help about_signing を実行し、数画面分スクロールしてください。

スクリプトに署名する

証明書とスクリプト (必要に応じてテスト用に簡単なものを作成してもかまいません) を用意したら、スクリプトに署名する準備は完了です。Windows PowerShell では、驚くほど簡単にスクリプトへの署名を実行できます。次のコードを入力するだけで、署名は完了します。

$cert = @(gci cert:\currentuser\my
-codesigning)[0]
Set-AuthenticodeSignature myscript.ps1 $cert

最初の部分では、最初にインストールされたコード署名証明書を取得しています (複数の証明書がインストールされており、別の証明書を使用する場合は、"0" を適切な値に変更します)。次の部分では、ファイルに署名しています (もちろん、ファイル名は必要に応じて変更してください)。以上で処理は完了です。しかし正直なところ、Set-AuthenticodeSignature というコマンドレット名は必要以上に長いと思います。そのため、Sign というエイリアスを作成しました。これで、次のコードを実行するだけで済みます。

Sign myscript.ps1 $cert

ここで、上記のスクリプトを開くと、最後に署名ブロックが挿入されているのを確認できます。実行ポリシーを AllSigned に設定してスクリプトを実行すると (Set-ExecutionPolicy AllSigned)、スクリプトは正しく動作します。次に、スクリプトを変更して保存します。ただし、今度は署名処理を実行しないようにします。署名が破損しているので、Windows PowerShell は、この変更後のスクリプトの実行を拒否します。

労力を費やす価値

ここで紹介したスクリプトの作成に費やす労力は、その価値に見合っているでしょうか。いくつかの管理タスクをスクリプト化することによって、500 ドルを費やして証明書を購入したり、まったく新しいインフラストラクチャ要素を実装したりする必要性をなくすということは、無理な要求でしょうか。私も管理者なので、管理者が抱える問題は理解しています。答えは簡単です。間違いなく、ありったけの労力を費やすだけの価値はあります。

実際、セキュリティには、ほぼ必ずある程度の煩わしさが伴います。ウイルス対策ソフトウェアは悩みの種になりますが、それなしでコンピュータを実行することはありません。また、ファイアウォール ソフトウェアは確かに面倒ですが、ご存知のとおり、ファイアウォールなしでコンピュータを実行するのは危険です。また、Windows Vista のユーザー アカウント制御 (UAC) も面倒ですが、これによってコンピュータの安全性が保たれます。そして、この強化されたセキュリティこそが、まさに私たちが実現しようとしていることではないでしょうか。

Windows PowerShell は強力なツールです。そして、他のあらゆるツールと同様、常に、悪意のあるユーザーによって、セキュリティの脆弱性を利用するための手段へとねじ曲げられる可能性があります。このため、そういった悪意のあるユーザーによる攻撃を阻止するための手段を講じることが重要です。

コードへの署名は最適な対策であり、それほど煩わしさもありません。たとえば、私は [Save] (上書き保存) をクリックするたびにスクリプトへの署名が自動的に実行されるグラフィカルなスクリプト エディタを使用しているので、ほとんど意識することなくコードに署名できます。

特別なエディタを使用しなくても、より透過的にコードに署名できます。たとえば、独自の Windows PowerShell プロファイルを作成し (ドキュメント フォルダの WindowsPowerShell という名前のフォルダに Microsoft.PowerShell_profile.ps1 ファイルを作成します)、次の関数を追加します。

function sign ($filename) {
  $cert = @(gci cert:\currentuser\my 
-codesigning)[0]
Set-AuthenticodeSignature $filename $cert
}

あとは、次のコードを入力するだけでスクリプトに署名できます。

Sign c:\scripts\myscript.ps1

そうですね、このプロファイル スクリプトが初めて署名したスクリプトということになります。煩わしさをなくすには、いくつかの手順を実行して、スクリプトへの署名をできるだけ簡単な操作にする必要があります。

コード署名証明書を発行するというだけの目的であれば、1 台の PKI サーバーを展開する作業はそれほど大変ではありません (ただし、特にルート CA の保護や障害回復機能の提供など、PKI を他の目的で使用する場合は、PKI に関するより詳細な調査を行い、綿密な計画を立てる必要があります)。環境内でスクリプトを実行するのが自分のみである場合は、Makecert.exe を使用します。Get-Help about_signing によって表示されるヘルプ トピックには、Makecert.exe によって生成された証明書のセキュリティ保護に関する情報も含まれています。

Don Jones は、『Windows PowerShell: TFM』と『VBScript, WMI, and ADSI Unleashed』の著者です。**連絡先については、PowerShellCommunity.org を参照してください。

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; 許可なしに一部または全体を複製することは禁止されています.