1. ホーム
  2. スクリプト・コラム
  3. パワーシェル

Powershellスクリプトに電子署名を行う方法

2022-01-04 01:56:48

スクリプトは平文で構成されているため、簡単になりすましや改ざんをされる可能性があります。デジタル署名は、スクリプトとスクリプトの編集者を一意に識別し、改ざんできないため、スクリプトに高いレベルのセキュリティを提供します。スクリプトの発行者として、自分のスクリプトが悪意を持って改ざんされていないことを確認することができます。この仕組みは複雑な論理に基づいているため、専門家でもどうすることもできません。幸いなことに、実際には、このような詳細を掘り下げる必要はなく、Powershellスクリプトの署名の仕組みとプロセスをマスターすればよいのです。

適切な証明書を用意する

Powershellスクリプトは従来の紙の署名では署名できないので、「証明書」という別の道具が必要になります。証明書とは、秘密で安全な鍵のようなものです。証明書はあなたの個人的な電子的なアイデンティティです。この秘密鍵は、証明書の所有者だけがスクリプトに署名するために使用することを保証します。

証明書は mmc add 管理ユニットで見ることができますが、特に証明書を見るために Powershell でサポートされています。ローカルでサポートされている証明書は、仮想ドライブ cert: を介して表示することができます。

自己署名入り証明書の作成

自己署名入り証明書を作成するには、makecert.exeというマイクロソフトのツールを使用する必要があります。このツールは個別にダウンロードすることはできませんが、Microsoftの.NETフレームワークに含まれているので、すでにVisual studioがインストールされている場合は便利です。

{スタート スタート->すべてのプログラム->Microsoft Visual Studio 2010->Visual Studio Tools->Visual Studio Command Prompt (2010)

makecert.exe -pe -r -n "cn=MosserPowerShellTestCert" -eku 1.3.6.1.5.5.7.3.3 -ss "my"
Succeeded

ここで、-ekuパラメータに少し注意してください。1.3.6.1.5.5.7.3.3 であり、それ以外の場合、証明書の意図された目的の属性はコード署名ではありません。
上記で作成された証明書は、CurrentUserMyのパスに自動的に保存されます。これはPowershellで次のように見ることができます。

PS E:> ls cert:CurrentUserMy | where {$_.subject -eq "CN=MosserPowerShellTestCert"}

  Directory: Microsoft.PowerShell.SecurityCertificate::CurrentUserMy

Thumbprint Subject
---------- -------
BA61AF0B8A856422AD9EF86104C8CEDB2583A21A CN=MosserPowerShellTestCert

コードサイニング証明書の検証

コードサイニングに対応した証明書を見る
証明書の発行者、代表者、シリアル番号、フィンガープリントを表示します。

プレ ## View the certificate for the intended purpose of code signing: $certs = @(Dir cert:CurrentUserMy -codeSigningCert) "Found {0} code-signing certificates" -f $certs.count ## Find 1 code-signing certificate ## Select the certificate you just created $certificate=ls cert:CurrentUserMy | where {$_.subject -eq "CN=MosserPowerShellTestCert"} ## Representative of the certificate $certificate.subject # CN=MosserPowerShellTestCert ## The issuer of the certificate $certificate.issuer # CN=MosserPowerShellTestCert ## Serial number of the certificate, fingerprint $certificate | select SerialNumber,Thumbprint | fl * # SerialNumber : C23F35EA85D9A5AB466C07A7C0469A78 # Thumbprint : 586A4332F0528867DA6A0900FCF0938EDD277E22

証明書の信頼性を宣言する

証明書の種類や発行者名などを指定すると、証明書の生データ(RawData)が自動的に生成されることが分かります。こうすることで、あなたが他人になりすまして証明書を生成することも、他人があなたの名前になりすまして証明書を生成することもできなくなります。なお、以前に生成した証明書が信頼できるかどうかをPowershellで確認すると、答えは「No」である。

PS E:> $certificate.Verify()
False

先ほど生成した証明書はなぜ信頼されないのでしょうか?その答えは簡単な1つのステップで見つけることができます。.NETにはメソッドがあります。System.Security.dll.NET には、証明書をダイアログボックスで表示するための DisplayCertificate() というメソッドがあり、これは System.Security.dll.NET にあります。このdllはデフォルトでは参照されていませんので、参照を追加してから証明書ダイアログを表示する必要があります。

PS E:> [System.Reflection.Assembly]::LoadWithPartialName("System.Security")

GAC Version Location
--- ------- --------
True v2.0.50727 C:windowsassemblyGAC_MSILSystem.Security2.0.0.0__b03f5f7f11d50a3aSys...

[System.Security.Cryptography.x509Certificates.X509Certificate2UI]::DisplayCertificate($certificate)

画像

Powershell ビュー証明書が信頼されない

ダイアログボックスを表示します。この CA ルート証明書は信頼されていません。信頼できるようにするには、証明書を[信頼されたルート証明機関]ストアにインストールします。

そこで次に、証明書を信頼できるストアにコピーすることができます。これは、certmgr.mscを使用して手動で行うか、Powershellを使用して自動で行うことができます。

PS E:> $rootStore= New-Object system.security.cryptography.X509Certificates.x509Store("root","Curre
ntuser")
$rootStore.Open("ReadWrite")
$rootStore.Add($certificate)
$rootStore.Close()

Add操作が実行されると、確認ダイアログが表示されますので、確認してください。

次に、バリデーション情報を見てみます。

PS E:> $certificate.Verify()
True

Powershellスクリプトに署名する

Powershellスクリプトにデジタル署名を行うには、信頼できるコードサイニング証明書を見つけ、残りの作業をSet-AuthenticodeSignatureに任せるという2つのステップしかありません。

{{コード
{未定義

すべてのスクリプトファイルに再帰的に署名する

現在のファイル以下のすべてのスクリプトに署名する

PS E:> 'Write-Host "My first signing script"' > firstSignScript.ps1
PS E:> $certificate=ls cert:CurrentUserMy | where {$_.subject -eq "CN=MosserPowerShellTestCert"}
PS E:> Set-AuthenticodeSignature .firstSignScript.ps1 $certificate

  Directory: E:

SignerCertificate Status Path
----------------- ------ ----
586A4332F0528867DA6A0900FCF0938EDD277E22 Valid firstSignScript.ps1

PS E:> Get-Content .firstSignScript.ps1
Write-Host "My first signature script"

# SIG # Begin signature block
# MIIEIQYJKoZIhvcNAQcCoIIEEjCCBA4CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUnxRdr+yE6sFotfvZjfn8k15W
# OtigggI0MIICMDCCAZ2gAwIBAgIQwj816oXZpatGbAenwEaaeDAJBgUrDgMCHQUA
# MCMxITAfBgNVBAMTGE1vc3NlclBvd2VyU2hlbGxUZXN0Q2VydDAeFw0xMjA2MTYx
# MzAyMjZaFw0zOTEyMzEyMzU5NTlaMCMxITAfBgNVBAMTGE1vc3NlclBvd2VyU2hl
# bGxUZXN0Q2VydDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr/2eZ6iS3Zi4
# Q2RsXFPRmDynztxPwArZ6SK663R6X2Dfqwv+kuev4VbEHJ20Bvd9yLvCS4QgCCR6
# n0D+ELfBy6aRpst51dNKNGV74TZIBu1M5EKG2+didLrKTx3lwEC66Bl+QyFiOzcH
# ZhQcaZzgdx8m8EN10/B2cDg9Tm9ppQsCAwEAAaNtMGswEwYDVR0lBAwwCgYIKwYB
# BQUHAwMwVAYDVR0BBE0wS4AQjHzaaSg4KlNdyvIpJNjeiqElMCMxITAfBgNVBAMT
# GE1vc3NlclBvd2VyU2hlbGxUZXN0Q2VydIIQwj816oXZpatGbAenwEaaeDAJBgUr
# DgMCHQUAA4GBAFA3lvWcbA8mWndKdIOCzQUbC9/+1vIeQRGaH7L6U6OHZuV2IBw1
# EpLxz1/dyFEMNZmy9z+/YjfJi774UY1eTzOJnz0AYKGPpM0BK2ieGZzPDIlbkpv1
# ywrv5BtRt053MNHRYaZQP0v9Sp6pOB4h10tKnvh0DW882zRPeB4hkK+fMYIBVzCC
# AVMCAQEwNzAjMSEwHwYDVQQDExhNb3NzZXJQb3dlclNoZWxsVGVzdENlcnQCEMI/
# NeqF2aWrRmwHp8BGmngwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKA
# AKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFMgyEZ64UFors3z9JGuKLVxh
# P2hLMA0GCSqGSIb3DQEBAQUABIGAMHFJHMVlauxKGIo2p9ieFBVp4Am6n533k89j
# 7pQXKOGmU/sG9d8PILifHLJZw7BU66+uZFvOSXlUxvqaPRAdeosc2BLDPf5Cu6o7
# 61BfSJc2H5dQCgbK/90OKmeJp4KJQRCk7HLEBvV23ddVSyl4CPplbUcTVmo92Zd1
# B/Moxro=
# SIG # End signature block

お望みなら、再帰的に

PS E:> Set-AuthenticodeSignature (ls *.ps1) $certificate

  Directory: E:

SignerCertificate Status Path
----------------- ------ ----
586A4332F0528867DA6A0900FCF0938EDD277E22 Valid firstSignScript.ps1
586A4332F0528867DA6A0900FCF0938EDD277E22 Valid MyScript.ps1
586A4332F0528867DA6A0900FCF0938EDD277E22 Valid pipeline.ps1
586A4332F0528867DA6A0900FCF0938EDD277E22 Valid PSLib.ps1

ダイアログボックスを使用して、証明書を選択します

マシンに多くのコードサイニング用証明書がインストールされている場合、friendNameまたは証明書の名前、および証明書のフィンガープリントによって、スクリプトサイニング用の証明書をフィルタリングすることができます。

Set-AuthenticodeSignature (Dir -recurse -include *.ps1) $certificate

もう一つの選択方法は、.NETの組み込みダイアログを利用する方法です。クエリされた証明書を SelectFromCollection() メソッドに渡します。これを実行する前に、証明書を特別なコレクションに配置する必要があります。

 Dir cert:CurrentUserMy |
 where {$_.subject -eq "CN=MosserPowerShellTestCert"}

画像

Powershel l 証明書を選択するダイアログボックス

Powershellスクリプトの署名検証

スクリプトに署名することで具体的に何ができるようになるかというと、検証することができるようになります。手動で検証することもできますし、自動的に検証することもできます。署名の検証は、そのスクリプトが信頼できるものか、それとも悪意のある改ざんが含まれているのかを教えてくれる。

ユーザーの自己検証。手動検証では、スクリプトに署名されたコードが含まれているかどうか、そしてその署名者が誰であるかをチェックします。その署名者が信頼できるかどうか。
自動検証を行います。Powershellのスクリプト実行ポリシーをAllSignedに設定した場合。Powershellはスクリプトを実行しようとすると、コードとスクリプトの署名が一致するかどうかを自動的に検証します。そして、署名者が信頼できるかどうかを尋ねてきます。

手動検証

Get-AuthenticodeSignatureコマンドは、署名を検証するコマンドです。例えば、署名のないスクリプトを作成し、このコマンドで検証します。StatusMessage属性で、署名の検証結果を知ることができます。

# Dialog box text:
$title = "Available certificates"
$text = "Please select a certificate for code signing:"
# Find certificates:
$certificates = Dir cert: -recurse -codeSigningCert
# Load the System.Security class library
# Store the certificates in a special collection (X509Certificate2Collection):
[Reflection.Assembly]::LoadWithPartialName("System.Security")
$collection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$certificates | ForEach-Object { $collection.Add($_) }
# Show options:
$certificate = [System.Security.Cryptography.x509Certificates.X509Certificate2UI]::`
SelectFromCollection($collection, $title, $text, 0)
# Use the selected certificate for digital signing
Set-AuthenticodeSignature -Certificate $certificate[0] -FilePath .firstSignScript.ps1

この無署名スクリプトを実行した場合、StatusMessageに含まれるメッセージであるエラーメッセージも表示されます。スクリプトの検証結果のステータスは以下の通りです。

{を使用します。 説明
メンバー名
ハッシュミスマッチ {を使用します。 ファイルのハッシュコードと保存された署名が一致しない {を使用します。
互換性がない 現在のOSと互換性がないため、署名が検証できません。
NotSigned ファイルには署名がありません
非対応のファイル形式 指定されたファイル形式は、システム署名でサポートされていません。これは通常、システムがファイルの種類を署名または検証する方法を知らないことを意味します。
信頼できない 証明書の発行者がシステムで信頼されていない。
不明なエラー 無効なファイル署名
有効 このファイルは有効な署名を持っています。これは、署名だけが構文的に合法であることを意味します。これは、信頼を意味するものではありません。

オートバリデーション

スクリプトの署名を検証する必要はなく、スクリプトを実行するとPowershellが自動的に検証を行います。スクリプトが検証されていても、その一部が更新されると自動検証は警告を出します。
自動検証は、ユーザーがスクリプトの実行ポリシーを AllSigned および RemoteSigned に設定したときに有効になります。実行ポリシーが AllSigned に設定されている場合、すべてのスクリプトが検証されます。RemoteSignedを選択すると、ネットワークからダウンロードしたスクリプトの実行時に署名の入力が求められます。

 "'unsigned'" >notsign.ps1
$checkResult=Get-AuthenticodeSignature .notsign.ps1
$checkResult.Status
NotSigned
$checkResult.StatusMessage
The file E:notsign.ps1 is not digitally signed. The system will not execute the script. For more information, see "get-help about_signing"
.
CheckResult.Status.GetType().fullName
System.Management.Automation.SignatureStatus

Windows PowerShellは、実行されたスクリプトがデジタル署名されていないことを示します。

署名されていないスクリプトを実行するか、スクリプトに署名するように設定してください。

# Set ExecutionPolicy to AllSigned. all # Scripts must have the correct signatures: Set-ExecutionPolicy AllSigned # Create a script without a signature. # The script will not execute: The file E:unSigned.ps1 cannot be loaded. file E:unSigned.ps1 is not digitally signed. The system will not execute the script. For more information, see Please see "get-help about_signing" for more information. Location Line:1 Character: 15 + .unSigned.ps1 < <<< + CategoryInfo : NotSpecified: (:) [], PSSecurityException + FullyQualifiedErrorId : RuntimeException Even if the signature can be verified, it requires user approval before it can be executed. .firstSignScript.ps1 Do I want to run software from this untrusted publisher? The file E:firstSignScript.ps1 is published by CN=MosserPowerShellTestCert published by CN=MosserPowerShellTestCert, this file is not trusted for your system. Please only run scripts from trusted publishers. [V] Never run(V) [D] Do not run(D) [R] Run once(R) [A] Always run(A) [?] Help (default value is "D"): a My first signature script # Run a second time without asking My first signature script

これで記事は終わりですので、必要な方はご参照ください。