WCFの.svcファイルは署名できる?改ざん防止とMicrosoft推奨アーキテクチャ完全ガイド(Azure Key Vault/HSM対応)

WCF の運用現場でしばしば議論になるのが「.svc ファイルをどう守るか」。結論から言えば、.svc を SignTool で直接署名することはできません。しかし、Microsoft が用意している“署名の土俵”に載せて間接的に保護する設計に切り替えれば、改ざん検知・追跡性・自動化のいずれも高いレベルで満たせます。本稿は、その背景と実装手順を Azure Key Vault(HSM/秘密鍵エクスポート不可)前提で徹底解説します。

目次

.svc ファイルを直接署名できない理由とリスク

.svc は WCF サービスのエンドポイントを ASP.NET/IIS に伝えるテキストファイルです。Authenticode(Windows のコード署名)が想定する“埋め込み署名”対象に .svc は含まれておらず、Windows/IIS が検証に使う SIP(Subject Interface Package)も提供されていません。つまり、.svc 単体へのデジタル署名は不可です。

では何が危険か。例として以下の改ざんが挙げられます。

  • サービスクラス名のすり替え(攻撃者製 DLL への迂回)
  • Factory 指定の変更(任意ロジックの注入)
  • バインディングやアドレスの変更による機密情報の漏えい

これらは .svc の内容が数行変わるだけで成立し、アセンブリ署名だけでは検出できません。したがって、ファイル群(=デプロイ単位)に対して OS が理解する方式で署名・検証するのが現実解です。

結論の要約(実務テーブル)

課題結論 / 推奨策補足ポイント
.svc を SignTool で直接署名できるか不可。Authenticode の対象外。検証用 SIP も存在しない。独自 SIP 実装は理論上可能だが運用・互換性リスクが大きく非推奨。
改ざん防止の推奨間接保護:
① 署名付きパッケージへ同梱(MSI/MSIX/VSIX 等)
② カタログ署名(.cat)でファイル群のハッシュを束ねて署名
③ 署名済みハッシュマニフェストを配布し、デプロイで照合
Windows の検証 API(WinVerifyTrust 等)や PowerShell の Test-FileCatalog が利用可能。
Azure Key Vault HSM(鍵エクスポート不可)での署名可能。
AzureSignTool もしくは Microsoft Trusted Signing を CI/CD から利用。
マネージド ID / OIDC を使えば資格情報のハードコード不要。

Microsoft 推奨の「間接的な保護」アーキテクチャ

“ファイルに直接署名できないなら、OS が理解できる入れ物 or カタログにまとめて署名する”。これが王道です。用途別の選び方は次のとおり。

方式適用範囲メリット注意点主な検証手段
パッケージ署名(MSI/MSIX 等)インストーラ配布型。Web サイトや Windows サービス一式。署名検証が OS/インストーラに統合。配布追跡・ロールバック容易。パッケージ作成の導入コスト。Web 配置の即時性はやや低下。インストール時の署名検証(UI/ポリシー)。signtool verify
カタログ署名(.cat).svc を含む“任意のファイル群”。ZIP も含め可。Web 配置と相性良い。差分デプロイでも検証できる。展開後に Test-FileCatalog 等で検証を必ず自動化。Test-FileCatalog / WinVerifyTrust / signtool verify /v /kp
署名付きハッシュマニフェストGitOps/CI で生成した JSON などの一覧。軽量・可読。差分照合が速い。検証コードの整備が必要。マニフェスト自体の署名・保護を忘れずに。Get-FileHash + Set-AuthenticodeSignature の二段構え

もっとも導入しやすく、運用の癖が少ないのはカタログ署名です。.svc を含む Web コンテンツ一式のハッシュを .cat に登録して署名し、デプロイ先で照合すれば改ざんを高精度に検知できます。

Azure Key Vault(HSM)前提での署名選択肢

1) AzureSignTool を使って Key Vault の鍵で署名

オープンソースの AzureSignTool は、Key Vault に格納した“エクスポート不可鍵”で .exe/.dll/.cat などを署名できます。CI からはマネージド ID または OIDC(GitHub Actions/Azure Pipelines)で認証し、秘密鍵を一切持ち出さずに運用可能です。

最小構成(カタログ署名)

  1. Key Vault にコード署名用証明書(鍵は HSM で非エクスポート)を作成またはインポート。
  2. ビルド成果のルートに対して PowerShell で .cat を生成。
  3. AzureSignTool で .cat に署名(RFC3161 タイムスタンプ付与)。
  4. デプロイ後に Test-FileCatalog で照合。NG ならデプロイ中断。

PowerShell:カタログの生成と検証

# 1) 署名対象フォルダ(Web ルート)のカタログ生成
$siteRoot = "C:\a\build\drop\WebSite"
$catPath  = "C:\a\build\drop\WebSite.cat"
New-FileCatalog -Path $siteRoot -CatalogFilePath $catPath -CatalogVersion 2

# 2) ここで AzureSignTool で .cat を署名(次のセクション参照)

# 3) (デプロイ先)検証:すべてのファイルが一致するか

$deployedRoot = "D:\inetpub\wwwroot\MySite"
$result = Test-FileCatalog -CatalogFilePath $catPath -Path $deployedRoot
if (-not $result.Result) { throw "Catalog verification failed. Deploy aborted." } 

AzureSignTool:Key Vault の証明書で署名

# 例: マネージド ID(システム割り当て)を使用して .cat に署名
AzureSignTool sign `
  -kvu https://<your-vault-name>.vault.azure.net/ `
  -kvc <CertNameInKeyVault> `
  -kvm true `
  -tr http://timestamp.digicert.com `
  -td sha256 `
  -fd sha256 `
  "C:\a\build\drop\WebSite.cat"

※ サービス接続/OIDC を使う場合は -kvi(ClientId), -kvt(TenantId)や -kvs(Client Secret)等を指定します。タイムスタンプは RFC3161(-tr)で SHA‑256(-td)を推奨。

2) Microsoft Trusted Signing(クラウド署名)を使う

Microsoft が提供するクラウド署名サービス(旧称 Azure Code Signing)を利用すると、証明書プロファイルを用意するだけで signtool 互換のワークフローをクラウド完結で構築できます。Key Vault を直接触らずに運用でき、証明書ローテーションや失効管理も一元化しやすいのが特長です。.cat や MSI 等のパッケージ署名をこのサービス経由で行うのが実務上の落としどころです。

CI からはワークロード ID 連携(例:GitHub OIDC / Azure Pipelines サービス接続)を使い、ジョブ内で signtool コマンドを呼び出します。社内ポリシーで「署名は Trusted Signing で統一、Key Vault 直接利用は禁止」といった整理も可能です。

実践:CI/CD への組み込み(完全自動化パターン)

パイプライン全体像

  1. ビルド:WCF サービスをコンパイルし、Web 配置アーティファクトを生成。
  2. カタログ生成:New-FileCatalog で .svc を含む全ファイルのハッシュを収集。
  3. 署名:AzureSignTool もしくは Trusted Signing で .cat に署名。タイムスタンプ必須。
  4. 配布:署名済み .cat とファイル群をまとめて転送(ストレージ・エージェント経由)。
  5. 検証:デプロイ先で Test-FileCatalog を実行。NG の場合は即ロールバック。

GitHub Actions(AzureSignTool 例)

name: build-and-sign
on: [push]
jobs:
  sign:
    runs-on: windows-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v4

```
  - name: Build
    run: |
      msbuild .\MySolution.sln /p:Configuration=Release

  - name: New File Catalog
    shell: powershell
    run: |
      New-FileCatalog -Path .\drop\WebSite `
        -CatalogFilePath .\drop\WebSite.cat -CatalogVersion 2

  - name: Azure Login (OIDC)
    uses: azure/login@v2
    with:
      client-id: ${{ secrets.AZURE_CLIENT_ID }}
      tenant-id: ${{ secrets.AZURE_TENANT_ID }}
      subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

  - name: Sign catalog with AzureSignTool
    run: |
      choco install azuresigntool -y
      AzureSignTool sign ^
        -kvu https://<vault>.vault.azure.net/ ^
        -kvi $env:AZURE_CLIENT_ID ^
        -kvt $env:AZURE_TENANT_ID ^
        -kvc <CertName> ^
        -tr http://timestamp.digicert.com ^
        -td sha256 -fd sha256 ^
        .\drop\WebSite.cat
```

Azure Pipelines(Trusted Signing 例の概念)

steps:
- powershell: |
    New-FileCatalog -Path $(Build.ArtifactStagingDirectory)\WebSite `
      -CatalogFilePath $(Build.ArtifactStagingDirectory)\WebSite.cat -CatalogVersion 2
  displayName: 'Create catalog'

# Trusted Signing による署名(サービス接続で OIDC 認証)

* task: PowerShell@2
  displayName: 'Sign catalog via Trusted Signing'
  inputs:
  targetType: 'inline'
  script: |
  # 環境に用意済みの signtool を使用するイメージ
  $cat = "$(Build.ArtifactStagingDirectory)\WebSite.cat"
  & "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe" sign `      /fd sha256 /td sha256`
  /tr [http://timestamp.digicert.com](http://timestamp.digicert.com) `
  $cat 

※ Trusted Signing の具体的なコマンド引数は組織のプロファイル設定に依存します。署名ポリシー(用途、発行名、タイムスタンプ要件など)を満たすよう、発行プロファイルとパイプライン権限を合わせ込みます。

デプロイ先での自動検証(改ざん検知の最終関門)

署名は“配布物の真正性”を担保しますが、実際に配置されたファイル群が署名対象と一致しているかを確認しない限り目的は達成できません。IIS サーバーでは、デプロイ完了直後に下記のヘルスチェックを必ず入れましょう。

param(
  [string]$SiteRoot = "D:\inetpub\wwwroot\MySite",
  [string]$Catalog  = "D:\packages\WebSite.cat"
)

$verify = Test-FileCatalog -CatalogFilePath $Catalog -Path $SiteRoot
if (-not $verify.Result) {
Write-Error "File catalog mismatch detected. Rolling back..."

# ロールバック処理(例:前バージョンへスイッチ)

exit 1
}

# 追加チェック:重要ファイルのハッシュピン留め(任意)

$svcExpected = "8C7A...F1" # ビルド時に埋め込んだ SHA-256
$svcActual   = (Get-FileHash (Join-Path $SiteRoot "Service.svc") -Algorithm SHA256).Hash
if ($svcExpected -ne $svcActual) {
Write-Error ".svc hash mismatch."
exit 1
} 

運用では、検証が失敗したらトラフィックを流す前に必ず停止(スロット/ブルーグリーン切替前で止める)というフローにしておくと安全です。

セキュリティ強化:ゼロトラストの観点で“多層防御”を重ねる

  • NTFS 権限の最小化:Web ルートは AppPool ID に読み取りのみ、更新はデプロイエージェント専用アカウントに限定。
  • 変更監査(SACL):.svc と web.config に「成功/失敗の書き込み」を監査設定。SIEM に転送。
  • WDAC/AppLocker:w3wp.exe が読み込める DLL を「署名済み・所定パスのみ」に制限。
  • アセンブリの強名署名:CLR による整合性検査を活用(セキュリティ境界ではないが改ざん検出に有効)。
  • 設定保護:機密セクションは aspnet_regiis 等で暗号化。機密値は Key Vault から取得。
  • 起動時の自己診断:アプリ起動時に .svc の想定クラス名・ファクトリ・バインディングを検査するヘルスチェックを実装。

“よくある誤解”とアンチパターン

誤解 / 盲点なぜダメか代替案
.svc をスクリプト署名(Set-AuthenticodeSignature)できるのでは?.svc はスクリプトホストの検証対象ではないため意味がない。カタログ署名 or パッケージ署名に切り替える。
ZIP 自体を直接 Authenticode 署名ZIP は PE ではないため“埋め込み署名”不可。ZIP の ハッシュをカタログに登録し、.cat を署名。
DLL に署名しているから十分.svc 改ざんで別 DLL を読ませればすり抜ける。設定側の完全性も必要。配置単位(コンテンツ一式)でハッシュ整合性を取る。
検証は手動チェックで十分人的作業は抜け漏れの温床。攻撃は数秒で成立。CI/CD とリリースゲートに自動検証を組み込む。

運用ドキュメントに残すべき“決めごと”チェックリスト

  • 署名方式:カタログ署名/パッケージ署名/両方のハイブリッド
  • 署名プロバイダー:AzureSignTool(Key Vault)/ Trusted Signing
  • 鍵管理:誰が作成・ローテーションし、どのロールが署名を実行できるか
  • タイムスタンプ:RFC3161、SHA‑256、タイムスタンプ必須
  • 検証タイミング:デプロイ直後、スロット切替前、起動後ヘルスチェック
  • 失敗時の動作:自動ロールバック/スロット切り戻し/アラート
  • ログ保全:署名ログ、Key Vault 監査ログ、CI/CD 実行ログの保管期間

実装レシピ:今日から使える“最短ルート”

  1. 証明書を用意:Key Vault(HSM)にコード署名証明書を作成。発行者・有効期限・EKU を社内規定に合わせる。
  2. CI に権限付与:マネージド ID / OIDC で署名 API(sign)を実行できるロールを付与。
  3. カタログ生成:New-FileCatalog をビルドの最後に実行。
  4. 署名:AzureSignTool もしくは Trusted Signing で .cat を署名(/fd sha256・/tr 指定)。
  5. 配布:アプリ本体と .cat を同梱してリリース。
  6. 検証:Test-FileCatalog で照合。不一致ならリリース中断。
  7. 監査:Key Vault の署名操作ログ・CI の実行ログを保全。

発展編:.svc を使わない構成や補強策

  • ルーティングホスト:ServiceRoute を用い、.svc を介さずにルーティングで WCF を公開(.NET Framework の範囲で可能)。ただし既存資産の移行コストを要検討。
  • プリコンパイル:Web サイトをプリコンパイルし、配置物の可変箇所を縮小。改ざん面積を減らす。
  • 構成の外部化:本番に依存する URL・資格情報は secret store(Key Vault)から取得。web.config の平文機密を排除。

トラブルシュート:署名・検証が失敗するとき

症状原因候補対処
signtool の検証で “A certificate chain processed, but terminated in a root store that is not trusted.”ルート/中間 CA の信頼が欠落配布先サーバーに信頼チェーンを配布。企業内 CA の場合は GPO で展開。
Test-FileCatalog が False を返す配布中の差分更新で一部ファイルが欠落/余剰カタログ生成と同一レイアウトで配布する。差分配布ツールの除外設定を見直す。
AzureSignTool が Key Vault にアクセスできないロール不足 / ファイアウォール / 認可境界キー操作 sign の権限を持つロールを付与。プライベートエンドポイント/Firewall を確認。
タイムスタンプに失敗するネットワーク遮断 / URL ミスRFC3161 エンドポイントを利用。プロキシ設定を確認し、-tr と -td sha256 を明示。

まとめ:.svc は“直接”ではなく“正しい土俵”で守る

.svc 自体を署名できないという制約はありますが、署名付きパッケージ、カタログ署名、署名済みハッシュマニフェストのいずれか(多くの現場ではカタログ署名)を導入し、CI/CD に自動検証を組み込めば、改ざんを高い確度で検出し、安全にロールバックできます。鍵は Azure Key Vault HSM に閉じ込め、AzureSignTool または Microsoft Trusted Signing を使って“鍵を出さない署名”を徹底しましょう。これが Microsoft のエコシステムに沿った、現代的で保守しやすい防御線です。

付録:現場でそのまま使えるスクリプト断片

カタログ生成と署名(ビルドステージ)

# 変数
$Root = "$(Build.SourcesDirectory)\drop\WebSite"
$Cat  = "$(Build.ArtifactStagingDirectory)\WebSite.cat"

# カタログ生成

New-FileCatalog -Path $Root -CatalogFilePath $Cat -CatalogVersion 2

# 署名(AzureSignTool の例)

AzureSignTool sign `  -kvu https://<vault>.vault.azure.net/`
-kvc  -kvm true `  -tr http://timestamp.digicert.com -td sha256 -fd sha256`
$Cat 

配置直後の検証と障害時ロールバック

$AppRoot = "D:\inetpub\wwwroot\MySite"
$SignedCat = "D:\packages\WebSite.cat"

$result = Test-FileCatalog -CatalogFilePath $SignedCat -Path $AppRoot
if (-not $result.Result) {

# ログ採取

Copy-Item $SignedCat "D:\logs\failed\WebSite.cat"
Get-ChildItem $AppRoot -Recurse | Get-FileHash -Algorithm SHA256 |
Export-Csv "D:\logs\failed\hashes.csv" -NoTypeInformation

# 切り戻し

& "C:\tools\switch-slot.ps1" -Target "previous"
exit 1
} 

重要ファイルをピン留め(ハイブリッド検証)

$pins = @{
  "Service.svc"     = "A1B2C3...";  # ビルド時に埋め込んだ SHA-256
  "web.config"      = "D4E5F6...";
  "bin\MyService.dll" = "0A1B2C..."
}

$root = "D:\inetpub\wwwroot\MySite"
foreach ($kv in $pins.GetEnumerator()) {
$path = Join-Path $root $kv.Key
$hash = (Get-FileHash $path -Algorithm SHA256).Hash
if ($hash -ne $kv.Value) { throw "Pinned file changed: $($kv.Key)" }
} 

FAQ(意思決定を速くするための追記)

Q. .svc を守るだけならハッシュだけで十分では? A. ハッシュだけでは生成者の真正性が担保されません。ハッシュファイル自体の改ざんも考慮が必要です。署名付きカタログ/マニフェストを推奨します。 Q. カタログ署名と MSI 署名はどちらを選ぶべき? A. デプロイ形態で選びます。IIS へのコピー配布主体なら .cat、エンドポイントにインストーラ配布なら MSI が自然です。併用も可です。 Q. 強名署名で DLL 改ざんは検出できますか? A. はい、CLR は読み込み時に強名を検証します。ただしセキュリティ境界ではないため、.svc 側の誘導で“別の DLL を読み込ませる”攻撃は別対策(本稿の手法)が必要です。 Q. Trusted Signing と Key Vault 直署名の違いは? A. 前者はクラウド署名サービスで、証明書プロファイル管理・監査の一元化に強み。後者は既存の Key Vault 設計に馴染む柔軟性が強みです。

ポリシー雛形(社内標準のひな形として)

目的: WCF (.svc) を含む配布物の完全性と正当性を保証する
方式: カタログ署名(.cat)を必須。場合により MSI 署名を追加。
鍵管理: Azure Key Vault HSM を使用。鍵エクスポート禁止。監査ログ保全 365 日。
署名要件: SHA-256 / RFC3161 タイムスタンプ必須。証明書の発行者と用途は社内 CA 規定に従う。
検証: デプロイ直後、スロット切替前に Test-FileCatalog を自動実行し、失敗時は自動切戻し。
例外: 緊急パッチ時はセキュリティ責任者の承認必須。48 時間以内に再署名・再配布。

最後に

.svc を直接署名できない――それ自体は制約に見えますが、視点を“配布単位の完全性”へ切り替えれば、より堅牢で自動化しやすい設計に昇華できます。Azure Key Vault HSM と CI/CD を土台に、カタログ署名+デプロイ時検証という現実解を今日から適用してください。攻撃者は数行の改ざんで侵入しますが、あなたの環境は 1 行のポリシーで守れます。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次