【スクリプト電子署名】Signer オブジェクトと連携したVBScriptコードへのデジタル署名検証と整合性チェック
開発プロジェクトのリーダーである私たちが、現場のメンバーによく言う言葉がある。
「動くコードを書くのはプログラマーの仕事だ。だが、『勝手に改ざんされないこと』を保証し、セキュアに稼働させ続けることは、プロフェッショナル・エンジニアの仕事だ」と。
業務自動化の現場において、VBScript(WSH)は今なお強力なカードだ。追加のランタイムをインストールせずとも、Windows環境さえあればタスクスケジューラと連携して骨太なバッチ処理を完遂できる。
しかし、その「手軽さ」ゆえの最大の弱点がセキュリティである。テキストファイルとして剥き出しで存在する `.vbs` は、悪意ある第三者(あるいは不心得な利用者)によって、いとも簡単にコードを書き換えられてしまう。パスワードのハードコーディング、不正なAPIエンドポイントへのすり替え――これらを防ぐ防壁がなければ、エンタープライズの自動化基盤としては失格だ。
今回は、Windows Script Host (WSH) が密かに内包する最高峰のセキュリティ機構、`Scripting.Signer` オブジェクトを用いたVBScriptのデジタル署名付与・検証・整合性チェックの極限知見を伝授する。
—
1. なぜ「剥き出しのVBScript」は危険なのか?
多くの現場では、VBScriptのセキュリティを「フォルダのアクセス権(ACL)」だけで担保しようとする。だが、それは幻想だ。
ネットワーク共有フォルダに置かれたスクリプト、ローカルの管理者権限を持つユーザー、あるいはシャドウITによる野良スクリプトの実行。これらはファイル権限をいとも簡単にすり抜ける。
ここで必要なのは、ファイルシステムへの依存ではなく、「コードそのものが証明書によって担保されているか」という暗号学的な整合性チェックである。
Scripting.Signer オブジェクトの本質
`Scripting.Signer` は、`.vbs` や `.js` といったWSHスクリプトファイルに対して、Authenticode形式のデジタル署名を付与し、かつその検証を行うためのCOMコンポーネントだ。
内部的にはCryptoAPIをラップしており、証明書ストアに紐づく信頼されたルート証明書をベースに、スクリプトが「誰によって書かれ」「署名以降に1バイトたりとも改ざんされていないか」を数学的に証明する。
—
2. 現場で使える!署名検証・整合性チェックのプロダクションコード
口を酸っぱくして言うが、セキュリティ機構は「エラーハンドリングをサボった瞬間にお飾りと化す」。
以下のコードは、指定されたVBScriptファイルのデジタル署名を厳密に検証し、改ざんや未署名を検知した場合は一切の実行を拒絶する、プロダクション品質の「セキュア・ローダー」である。
コピペしてそのまま現場の基盤に組み込んでほしい。
‘ ==============================================================================
‘ Script Name: SecureScriptLoader.vbs
‘ Description: 指定されたVBScriptファイルのデジタル署名を検証し、
‘ 整合性が確認された場合のみ実行するセキュアローダー
‘ ==============================================================================
Option Explicit
Const TARGET_SCRIPT = “C:\Automation\CoreProcess.vbs”
Const REQUIRE_VALID_SIGNATURE = True ‘ 本番環境では必ずTrueにすること
Sub Main()
Dim fso, shell
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set shell = CreateObject(“WScript.Shell”)
‘ 1. ターゲットファイルの存在確認
If Not fso.FileExists(TARGET_SCRIPT) Then
WScript.Echo “[FATAL ERROR] ターゲットスクリプトが見つかりません: ” & TARGET_SCRIPT
WScript.Quit 1
End If
‘ 2. デジタル署名の検証と整合性チェック
Dim isSignedAndValid
isSignedAndValid = VerifyScriptSignature(TARGET_SCRIPT)
If Not isSignedAndValid Then
If REQUIRE_VALID_SIGNATURE Then
WScript.Echo “[SECURITY ALERT] スクリプトのデジタル署名が無効、または改ざんされています。” & vbCrLf & _
“実行を強制中断します。”
‘ 異常終了コードを返す(タスクスケジューラの検知用)
WScript.Quit 99
Else
WScript.Echo “[WARNING] 署名が無効ですが、設定により実行を継続します。”
End If
Else
WScript.Echo “[INFO] デジタル署名の検証に成功しました。整合性は完全に保たれています。”
End If
‘ 3. 検証通過後に別プロセスとして安全に実行
‘ ※ 外部スクリプトに引数を渡す設計にする場合はここにパラメータを追加
Dim cmd
cmd = “cscript.exe //Nologo “”” & TARGET_SCRIPT & “”””
Dim exitCode
exitCode = shell.Run(cmd, 1, True)
WScript.Quit exitCode
End Sub
‘ ——————————————————————————
‘ Function: VerifyScriptSignature
‘ 概要: Scripting.Signer を用いてスクリプトの署名妥当性を検証する
‘ 戻り値: Boolean (True = 署名有効かつ改ざんなし, False = 無効/未署名/エラー)
‘ ——————————————————————————
Function VerifyScriptSignature(filePath)
On Error Resume Next
Dim signer, isValid
‘ Signer オブジェクトのインスタンス化
Set signer = CreateObject(“Scripting.Signer”)
If Err.Number <> 0 Then
WScript.Echo “[ERROR] Scripting.Signer の初期化に失敗しました。OSの環境を確認してください。Error: ” & Err.Description
VerifyScriptSignature = False
Exit Function
End If
‘ 署名の検証を実行
‘ 内部で証明書の失効チェックやルート証明書の信頼性を検証する
isValid = signer.VerifyFile(filePath)
If Err.Number <> 0 Then
‘ 署名が存在しない場合や、パースに失敗した場合のエラー捕捉
‘ ※ 未署名ファイルに対して VerifyFile を実行するとエラーが発生する仕様
VerifyScriptSignature = False
Err.Clear
Exit Function
End If
On Error GoTo 0
VerifyScriptSignature = isValid
End Function
‘ 実行のエントリーポイント呼び出し
Main()
—
3. 開発者・アーキテクトが押さえるべき設計上の急所
この仕組みを導入するにあたり、現場のエンジニアからよく出る疑問と、私たちがロジカルに返すべき「設計の急所」を解説する。
急所①:「未署名のファイル」をどう扱うか?
開発環境(ローカルPC)において、コードを修正するたびに正式なコードサイン証明書で署名し直すのは、開発効率を著しく落とす(アジャイルの敵だ)。
そのため、上記のコードにあるように `REQUIRE_VALID_SIGNATURE` のようなフラグ、あるいは環境変数や設定ファイルによるスイッチを用意し、「開発環境では署名なしを許容し、本番環境(PRD)のCI/CDパイプラインやタスクスケジューラ配下では厳格に拒絶する」という多層防御のスイッチング設計に落とし込むべきだ。
急所②:コードサイン証明書の調達と管理
`Scripting.Signer` が検証できるのは、Windowsの「証明書ストア(Personal / TrustedPublisher など)」に正しく紐づき、信頼されたルートから発行された証明書(または自己署名証明書で、信頼されたルート証明機関ストアにインポートされたもの)である。
業務自動化ツールであれば、社内のプライベートCA(認証局)から発行されたコードサイニング証明書を、実行するマシンの `TrustedPublisher`(信頼された発行元)ストアにインポートしておく必要がある。
【参考:自己署名証明書をPowerShellで作成しストアへ登録するコマンド(開発・検証用)】
自己署名コードサイン証明書の作成 (PowerShell)
$cert = New-SelfSignedCertificate -Type CodeSigningCert -DnsName “AutomationScriptRoot” -CertStoreLocation “Cert:\CurrentUser\My”
信頼された発行元ストアへエクスポート&インポート
Export-Certificate -Cert $cert -FilePath C:\Temp\autocert.cer
Import-Certificate -FilePath C:\Temp\autocert.cer -CertStoreLocation “Cert:\LocalMachine\TrustedPublisher”
※本番運用では、必ず社内インフラチームが管理する正式なコードサイニング証明書を使用すること。
急所③:署名(Sign)を自動化パイプラインに組み込む
人間が手動で署名作業を行う運用は、必ず属人化し、ヒューマンエラーを生む。
VBScriptへの署名自体も、ビルドスクリプト(PowerShell等)から `Set-AuthenticodeSignature` コマンドレットなどを用いて自動化するのがモダンなアプローチだ。
しかし、WSHの `Scripting.Signer` 自体には、プログラムから署名を付与するメソッド (`SignFile`) も用意されている。
‘ 【参考】スクリプト内からプログラム的に署名を付与する場合のコード
Sub SignMyScript(filePath, certSubjectName)
Dim signer
Set signer = CreateObject(“Scripting.Signer”)
‘ 第1引数: 証明書の件名(Subject)の一部、第2引数: タイムスタンプサーバーURL(任意)
signer.SignFile filePath, certSubjectName, “http://timestamp.digicert.com”
End Sub
※ただし、秘密鍵のアクセス権限管理の観点から、署名付与はビルドサーバー側(PowerShell)で行い、実行端末(WSH)側では `Scripting.Signer` による「検証」のみに特化させるのが、セキュリティアーキテクチャとしては最もクリーンである。
—
4. まとめ:野良スクリプトを根絶し、セキュアな自動化基盤へ
VBScriptはレガシーな言語だと言われることがある。だが、それは「適切に現代的なセキュリティガバナンスを効かせていない現場」の言い訳に過ぎない。
今回解説した `Scripting.Signer` を組み合わせた検証ロジックをプロジェクトの標準テンプレートとして組み込めば、以下のような圧倒的なメリットを手に入れることができる。
1. 改ざんの即時検知: 万が一、不正アクセスや誤操作でスクリプトが書き換えられた場合でも、実行前に確実に弾くことができる。
2. 責任の所在の明確化: 誰(どの証明書)によって署名されたコードなのかが暗号学的に担保されるため、監査要件を容易にクリアできる。
3. 自動化基盤の信頼性向上: 「動けばいい」から「安全でなければ動かさない」という、プロフェッショナルなエンジニアリング文化の定着。
コードの行数を減らすことだけが効率化ではない。「後から発生するセキュリティインシデントという最大のコスト」をゼロにする設計こそが、私たちエンジニアリングチームが追求すべき真の効率化である。
今すぐ君の現場のバッチリポジトリに、このセキュアローダーを組み込んでほしい。
