社内サーバーから配布した WinForms(C#)の ClickOnce アプリで「発行元不明」と表示され、ユーザーがインストールできない――。これは証明書と署名、そしてクライアント側の信頼チェーン設定が揃っていないことが原因です。本記事では、社内配布に最適な実装パターンと、具体的な手順・運用設計・トラブル対応までを一気通貫で解説します。
ClickOnce で配布する WinForms アプリの署名証明書問題
質問概要
- C# WinForms アプリを ClickOnce で社内サーバーから配布したところ、利用者 PC でインストール時に「発行元不明」の警告が出て実行できない。
- 社内配布でもコード署名は必要か?
- 必要なら具体的にどう準備・設定すればよいか?
結論(要点)
- ClickOnce の配置マニフェスト(.application)とアプリケーション マニフェスト(.manifest)は署名が必須。さらにEXE への Authenticode 署名も行うと SmartScreen の警告が大幅に減ります。
- 社内配布の場合でも、「信頼された発行元(証明書チェーン)」をクライアントへ配布しないと「発行元不明」になります。
- 運用は大きく社内 CA(または自己署名)と商用 CA の購入の2択。規模や将来拡張性で選びます。
なぜ「発行元不明」になるのか(仕組みの理解)
ClickOnce は信頼チェーンに基づいて配布元を判定します。配布元が信頼できるかは、署名に使われたコード署名証明書の発行元 CA(ルート/中間 CA)がクライアントにとって信頼済みかどうかで決まります。署名なし、または未知の CA で署名された場合、Windows は発行元を特定できず警告を出します。
| 対象 | 役割 | 署名の要否 | 備考 |
|---|---|---|---|
| 配置マニフェスト(.application) | インストーラー本体。更新元 URL や最小権限など。 | 必須 | ここが未署名だと即「発行元不明」。 |
| アプリケーション マニフェスト(.manifest) | 実行に必要なファイル一覧と要求権限。 | 必須 | ClickOnce の核。改変検出の要。 |
| 実行可能ファイル(.exe / .dll) | アプリ本体のバイナリ。 | 推奨 | Authenticode 署名で SmartScreen 対策・改ざん検出を強化。 |
回答・解決策(配布方式の比較)
| 選択肢 | 概要 | メリット | デメリット | 適するケース |
|---|---|---|---|---|
| ① 社内 CA または自己署名証明書 | AD CS や New‑SelfSignedCertificate 等で社内用の .pfx を発行し、ClickOnce マニフェストに署名。クライアント PC へ発行元 CA を「信頼されたルート証明機関」に配布(GPO/Intune 等)。 | 追加費用なし/社内ネットに閉じた運用が可能/短期間で導入可。 | 全クライアントに CA 証明書を配布する手間。社外では無効。CRL などの運用が必要。 | 完全に社内だけで使うアプリ/ユーザー数が限定的で GPO が効く環境。 |
| ② 商用 CA(DigiCert・Sectigo 等)のコード署名証明書 | 企業実在証明を経て EV Code Signing または通常 Code Signing 証明書を取得し、ClickOnce 署名や EXE 署名に利用。 | 既に Windows に信頼されており追加設定ほぼ不要。SmartScreen 警告が少ない(EV は特に有利)。 | 年額コスト/発行審査。近年はハードウェアトークンや HSM 前提で CI/CD 連携に工夫が必要。 | ユーザー母数が多い/将来社外配布の可能性/GPO 配布が困難な環境。 |
最短で効果を出す実装フロー(社内 CA/自己署名の例)
準備チェックリスト
- RSA 2048bit 以上、ハッシュは SHA‑256(SHA‑2)を使用。
- 拡張キー使用法(EKU):Code Signing(1.3.6.1.5.5.7.3.3)が含まれること。
- クライアントから CA のCRL(失効リスト)または OCSP に到達できること(内部 CA の場合)。
- 署名には .pfx(秘密鍵付き)、配布には .cer(公開鍵のみ)を使い分ける。
1. 証明書の作成(自己署名の例)
# 開発端末で自己署名のコード署名証明書を作成(有効期限は2年の例)
$cert = New‑SelfSignedCertificate `
-Subject "CN=Contoso Internal Code Signing" `
-Type CodeSigningCert `
-CertStoreLocation "cert:\CurrentUser\My" `
-KeyExportPolicy Exportable `
-KeyAlgorithm RSA `
-KeyLength 3072 `
-HashAlgorithm SHA256 `
-NotAfter (Get-Date).AddYears(2)
# 署名用に PFX をエクスポート(パスワードは保管庫で管理)
$pwd = Read-Host -AsSecureString "PFX Password"
Export-PfxCertificate -Cert $cert -FilePath "$env:USERPROFILE\Desktop\contoso-codesign.pfx" -Password $pwd
# クライアント配布用に CA/自己署名の CER も作成
Export-Certificate -Cert $cert -FilePath "$env:USERPROFILE\Desktop\contoso-codesign.cer"
AD CS を使う場合は「コード署名」テンプレートから申請し、発行された証明書を PFX と CER にエクスポートします。公開鍵側(CER)は GPO/Intune で配ります。
2. ClickOnce 署名(Visual Studio)
- プロジェクトを右クリック → 発行(または「発行プロファイル」)を開く。
- 高度な設定 → マニフェストを署名 → .pfx を選択しパスワードを入力。
- 配置マニフェストとアプリケーション マニフェストが新しい証明書で署名されます。
3. EXE への Authenticode 署名(推奨)
SmartScreen の誤検知を抑えるため、ClickOnce とは別に EXE/DLL 自体にも署名します(ビルド後タスクや CI/CD で自動化)。
# RFC3161 タイムスタンプを付与(有効期限切れ後も署名の有効性を保持)
signtool sign ^
/fd sha256 ^
/tr <タイムスタンプURL> ^
/td sha256 ^
/f "contoso-codesign.pfx" /p <PFXパスワード> ^
/v "bin\Release\MyApp.exe"
タイムスタンプ URL は組織のポリシーに合わせて指定します。タイムスタンプは必須です。
4. クライアント PC へ信頼配布(GPO の例)
- GPMC(グループ ポリシー管理)でドメイン GPO を作成。
- コンピューターの構成 → ポリシー → Windows 設定 → セキュリティの設定 → 公開キーのポリシーを開く。
- 信頼されたルート証明機関に CA(または自己署名)の CER をインポート。
- 可能なら信頼された発行元にも開発者証明書の CER を配布(署名者を明確に信頼させる目的)。
Intune の場合は「デバイス構成プロファイル(証明書)」で同等の配布が可能です。
5. 動作テスト
- クライアントで
certmgr.mscを開き、信頼されたルート証明機関/信頼された発行元に CER が入っているかを確認。 - ClickOnce のインストール画面に「発行元: Contoso Internal Code Signing」と表示され、警告が減っていれば成功。
- PowerShell で署名検証:
Get-AuthenticodeSignature .\MyApp.exe
商用 CA を使う場合(EV/通常コード署名)
- 組織名で申請・実在確認を完了。近年は秘密鍵のハードウェア保護(トークン/HSM)が要求されるため、CI/CD 連携方法をあらかじめ決めておきます。
- 発行された証明書(トークン配布またはクラウド署名)を署名用マシンから利用可能にする。
- Visual Studio のマニフェスト署名で証明書を選択し、ClickOnce を発行。
- EXE も合わせて
signtoolで署名(タイムスタンプ付与)。
signtool sign ^
/fd sha256 ^
/tr <タイムスタンプURL> /td sha256 ^
/a /v "bin\Release\MyApp.exe"
EV 証明書は SmartScreen の初期レピュテーションが得やすく、不特定多数へ配布する場合に有利です。社内配布でもユーザー数が多く、GPO 配布が難しい環境では管理コストを下げられます。
やってはいけない回避策
- レジストリやゾーン設定で警告そのものを抑止(クリックワンスの信頼プロンプト無効化など)。将来の更新で再びブロックされたり、別の攻撃面が開く恐れがあります。
- SSL サーバー証明書や S/MIME 証明書で代用。用途が違うため不可。必ず「コード署名」用途の証明書を用いること。
- EXE のみ署名してマニフェストは未署名。ClickOnce ではマニフェストの署名が本体です。
証明書の要件・選定基準
| 項目 | 要件/推奨 | 理由 |
|---|---|---|
| アルゴリズム | RSA 2048〜3072bit + SHA‑256 | Windows 10/11 の標準・長期サポート。 |
| EKU | Code Signing(1.3.6.1.5.5.7.3.3) | 署名用途の証明書であることを保証。 |
| タイムスタンプ | RFC3161 で必ず付与 | 証明書期限切れ後も署名の有効性を維持。 |
| 秘密鍵保護 | PFX の厳格管理/可能なら HSM/トークン | 漏洩リスク低減と監査性。 |
CI/CD への組み込み例
ビルドから署名、ClickOnce 発行までを自動化して人的ミスを防ぎます。以下は概念例(Windows ランナー想定)。
# 例: CI での概念ワークフロー(抜粋)
steps:
- name: Restore & Build
run: |
dotnet restore
dotnet build -c Release
* name: Sign binaries
run: |
signtool sign ^
/fd sha256 ^
/tr <タイムスタンプURL> /td sha256 ^
/f "$(PFX_PATH)" /p "$(PFX_PASSWORD)" ^
"src\MyApp\bin\Release\net48\MyApp.exe"
* name: Publish ClickOnce
run: |
msbuild src\MyApp\MyApp.csproj ^
/p:Configuration=Release ^
/p:PublishProfile=ClickOnceProfile ^
/p:ManifestCertificateThumbprint=$(CERT_THUMBPRINT)
署名鍵(PFX)はリポジトリに含めず、CI のシークレット管理に登録し、必要時だけ展開・使用・破棄します。
運用設計:証明書ローテーションと更新
- タイムスタンプ必須:既存バージョンは証明書失効後もインストール可能(安全性確保)。
- 別鍵=別アプリ扱いに注意:ClickOnce のアプリ ID は公開鍵(PublicKeyToken)に結びつくため、署名証明書の鍵を切り替えると更新経路が分断され、再インストールが必要になる場合があります。計画的な切替を。
- 同一サブジェクト名(CN)を継承しても、鍵が変われば ID は変わります。やむを得ず切替えるときは、旧版の最終バージョンを案内し、移行手順を明示しましょう。
トラブルシューティング(症状 → 原因 → 対処)
| 症状 | 主な原因 | 確認/コマンド | 対処 |
|---|---|---|---|
| 「発行元不明」 | 未署名/未知の CA/ルート未配布 | certmgr.mscでルート/発行元の有無を確認 | CA の CER を信頼されたルートと信頼された発行元に配布。 |
| SmartScreen が警告 | レピュテーション不足/EXE 未署名 | Get-AuthenticodeSignaturesigntool verify /pa /v MyApp.exe | EXE にも署名。EV 証明書や配布数の増加で改善。 |
| 「アプリケーションを起動できません」 | マニフェスト改変/署名破損 | mage -Verify 等で検証 | 再発行時は再署名。Zip 解凍・再圧縮などを避ける。 |
| 一部端末だけ警告が出る | 証明書ストアや CRL 参照不可 | certutil -urlfetch で到達性を確認 | プロキシ/ファイアウォール調整。オフライン端末は CRL キャッシュを配布。 |
| 署名はあるのに「不明」 | 署名は EXE のみ、マニフェスト未署名 | ClickOnce の発行プロファイル設定を確認 | 配置/アプリ マニフェストに署名を付与。 |
コマンド&ツールの実用スニペット集
署名済みかを PowerShell で確認
Get-AuthenticodeSignature .\publish\MyApp.application | Format-List
Get-AuthenticodeSignature .\bin\Release\MyApp.exe | Format-List
Mage.exe でマニフェストを署名/再署名
# アプリケーション マニフェストを署名
mage -Sign MyApp.exe.manifest -CertFile contoso-codesign.pfx -Password <PFXパスワード> -TimestampUri <タイムスタンプURL>
# 配置マニフェストを署名
mage -Sign MyApp.application -CertFile contoso-codesign.pfx -Password -TimestampUri <タイムスタンプURL>
GPO を使わずに一時的にローカルへ信頼追加(評価用)
# 管理者 PowerShell
certutil -addstore -f "Root" "C:\temp\contoso-codesign.cer"
certutil -addstore -f "TrustedPublisher" "C:\temp\contoso-codesign.cer"
本番では GPO/Intune で一括配布してください。
セキュリティとガバナンスの勘所
- 権限分離:署名鍵の保管者とビルド権限者を分ける。承認ワークフローを設ける。
- 鍵の棚卸し:PFX の所在、使用履歴、期限を台帳化。失効手順とインシデント対応訓練。
- CI の一時展開:署名時だけ PFX を復号し、処理後に即削除。ログにパスワードを残さない。
- 最小権限:ClickOnce の要求権限(UAC/管理者権限)を最小化。不要なフル トラストを避ける。
FAQ
Q. 社内配布でもコード署名は本当に必要?
A. 必須です。署名がないと配布元の改ざん検知と発行元の特定ができず、既定で警告やブロックの対象になります。クライアントに信頼されたルートを配布すれば社内でもスムーズに導入できます。
Q. EV と通常の違いは?
A. どちらも安全に署名できますが、EV は厳格な審査とハードウェア保護が前提で、SmartScreen の初期レピュテーションが得やすく、幅広いユーザーに配布する場合に有利です。社内限定なら通常証明書で十分なケースが多いです。
Q. 証明書の期限が切れたら過去のバージョンは使えなくなる?
A. タイムスタンプを付与していれば、有効期限切れ後でも署名時点の有効性が示されます。必ずタイムスタンプを付けてください。
Q. 証明書を切り替えたら更新できなくなった
A. ClickOnce のアプリ ID は公開鍵に結びつくため、鍵が変わると別アプリ扱いになることがあります。切替はメンテナンス期間に実施し、ユーザーに再インストールを案内する計画を。
Q. Edge/Chromium で ClickOnce は使える?
A. 可能です。企業ポリシーで ClickOnce 有効化やダウンロード動作を統制してください(ブラウザ側の設定配布)。
実践テンプレート:導入〜定着までのロードマップ
- 設計:社内か社外か、ユーザー数、更新頻度、CI/CD の有無を決める。
- 証明書選定:①社内 CA/自己署名 か ②商用 CA を決定。
- 署名フロー構築:Visual Studio のマニフェスト署名と
signtoolの EXE 署名をビルドに組み込む。 - 信頼配布:GPO/Intune で CER を「信頼されたルート/発行元」に展開。
- 検証:パイロット端末でインストール UI の発行元表示、SmartScreen の挙動、CRL 参照を確認。
- 運用:鍵・証明書の台帳、期限アラート、タイムスタンプ、インシデント時の失効手順を整備。
具体的な導入手順(要点再掲:社内 CA を使用)
- 証明書作成
New‑SelfSignedCertificate ` -Subject "CN=Contoso Internal Code Signing" ` -Type CodeSigningCert ` -CertStoreLocation "cert:\CurrentUser\My" ` -KeyExportPolicy Exportable ` -KeyLength 2048 ` -HashAlgorithm SHA256生成された証明書を .pfx でエクスポート。 - ClickOnce 署名
Visual Studio → プロジェクトの発行 → 高度な設定 → マニフェストを署名で先ほどの .pfx を指定。
さらに EXE をsigntool sign /fd sha256 /tr <タイムスタンプURL> /td sha256 /a MyApp.exeで署名。 - クライアント PC へ CA 配布
GPO:コンピューターの構成 → ポリシー → Windows 設定 → セキュリティの設定 → 公開キーのポリシー → 信頼されたルート証明機関に CA の .cer を登録。必要に応じて信頼された発行元にも登録。SCCM/Intune でも可。 - テスト
ClickOnce のインストール画面で「発行元: Contoso Internal Code Signing」と表示され、警告が減っていれば成功。
注意・補足(実務でハマりやすい点)
- セキュリティ設定を下げて警告を無効化する方法は推奨されません。将来の Windows 更新で再びブロックされる恐れがあり、監査上も問題になります。
- Windows 10/11 以降は SHA‑2(SHA256)・RSA 2048bit 以上の証明書が実質必須です。
- EV Code Signing を使うと SmartScreen の初期警告が出にくく、不特定多数に配布する場合にコストに見合う効果が期待できます。
- 署名後は、アプリやマニフェストを更新するたび再署名が必要。CI/CD に
signtoolとmageを組み込むと運用が安定します。 - 内部 CA ではCRL/OCSP の到達性が鍵。オフライン拠点がある場合は CRL のキャッシュやミラーを検討。
チェックリスト(配布前の最終確認)
- 配置/アプリ マニフェストに署名済み・タイムスタンプ済みか。
- EXE/DLL にも Authenticode 署名・タイムスタンプを付与したか。
- クライアントの「信頼されたルート/発行元」に正しい CER が配布されているか。
- オフライン/プロキシ環境でも CRL(または OCSP)が検証できるか。
- 証明書の期限アラート(90/60/30日前)とローテーション計画があるか。
- 署名鍵の保護(保管庫、権限分離、アクセス監査)が実装されているか。
まとめ
社内だけで使う小規模アプリなら社内 CA / 自己署名で十分ですが、クライアント PC への信頼ルート配布が必須です。ユーザー母数が多い、または将来的に社外配布の可能性がある場合は商用 CA のコード署名証明書の方が運用が楽で安全性も高まります。どちらの選択でも、マニフェストと EXE の二段構え署名+タイムスタンプ+鍵管理の徹底が成功のポイントです。

コメント