.NET 6 までは接続文字列に Encrypt を書かなくても SQL Server に普通に繋がっていたのに、.NET 8(EF Core 7/8)へ移行した途端に証明書エラーで接続できない――そんな相談が急増しています。原因は「ドライバー側の既定値が Encrypt=true に変わった」こと。この記事では、従来通りの動作をすぐに復旧する方法から、開発・本番での最適な暗号化設定、証明書導入の実務ポイントまで、現場の運用に耐えるレベルで徹底解説します。
.NET 8/EF Core 7 以降で何が変わったのか
SQL Server への接続を担うクライアント・ドライバー(Microsoft.Data.SqlClient)は、バージョン 4.x 以降で 既定値の Encrypt を false→true に変更しました。EF Core 7/8 もこれを取り込み、.NET 8 のアプリでは明示しない限り TLS による暗号化とサーバー証明書の検証が行われます。
- 接続文字列に
Encryptを書かない=Encrypt=trueと同義 - サーバー側に「信頼できる証明書」が無い/名前が一致しない → 証明書エラー
- よくあるエラー:“The certificate chain was issued by an authority that is not trusted.”、“A connection was successfully established with the server, but then an error occurred during the pre-login handshake.”
この挙動はセキュリティ強化のための仕様です。従来の「暗号化なし」が前提の接続文字列は、アップグレード後に見直しが必要になります。
すぐに使える対処パターン早見表
| 目的 | 接続文字列例 | 解説 |
|---|---|---|
| 従来通り暗号化なしで接続したい(暫定) | Server=servername;Database=dbname;Trusted_Connection=True;Encrypt=false | Encrypt を false に明示。既定値が true に変わったため、書かないと証明書検証が動いてエラーになります。 |
| 開発環境だけ証明書検証を無視して暗号化したい | Server=localhost;Database=dbname;Trusted_Connection=True;Encrypt=true;TrustServerCertificate=true | 通信自体は暗号化(TLS)のまま、TrustServerCertificate で証明書チェーン検証をスキップ。ローカル開発・CI向け。本番では非推奨。 |
| 本番環境で安全に暗号化したい | Encrypt=true を維持し、信頼されたサーバー証明書を SQL Server に導入 | ルート CA で信頼された証明書を使えば TrustServerCertificate は不要。FQDN の一致と SAN 設定が重要。 |
パラメータの意味と既定値(EF Core 7/8/Microsoft.Data.SqlClient)
| キー | 意味 | 既定値 | 注意点 |
|---|---|---|---|
Encrypt | ネットワーク通信を TLS で暗号化するか | true | 暗号化を無効化すると盗聴リスク。やむを得ない場合の暫定手段に限定。 |
TrustServerCertificate | サーバー証明書のチェーン検証を省略するか | false | 開発用途のみ推奨。本番で true は中間者攻撃に脆弱。 |
HostNameInCertificate | 証明書の CN/SAN として期待するホスト名を明示 | 未設定 | 接続で IP を使う場合やエイリアス使用時の“名前不一致”対策に有効。 |
Trusted_Connection / Integrated Security | Windows 認証の利用 | 未設定 | SQL 認証なら User ID と Password を使用。 |
環境ごとの接続文字列設計(安全な運用モデル)
構成ポリシー
- 開発:
Encrypt=true;TrustServerCertificate=true(ローカルや一時的な開発 DB)。 - ステージング:できる限り本番同等の正式証明書を配布。
TrustServerCertificate=false。 - 本番:
Encrypt=trueを堅持。信頼されたサーバー証明書を必須。
appsettings.*.json の例
環境ごとに接続文字列を分離します。ASP.NET Core なら環境変数 ASPNETCORE_ENVIRONMENT で自動切替できます。
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=SampleDb;Trusted_Connection=True;Encrypt=true;TrustServerCertificate=true"
}
}
{
"ConnectionStrings": {
"Default": "Server=stg-sql.example.local;Database=SampleDb;Encrypt=true;TrustServerCertificate=false"
}
}
{
"ConnectionStrings": {
"Default": "Server=prod-sql.example.com;Database=SampleDb;Encrypt=true"
}
}
EF Core(DbContext)での設定例
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(
builder.Configuration.GetConnectionString("Default"),
sql => sql.EnableRetryOnFailure())); // 接続自動再試行(推奨)
ADO.NET(SqlConnectionStringBuilder)での例
var csb = new SqlConnectionStringBuilder
{
DataSource = "prod-sql.example.com",
InitialCatalog = "SampleDb",
Encrypt = true,
TrustServerCertificate = false,
IntegratedSecurity = true
};
using var conn = new SqlConnection(csb.ConnectionString);
await conn.OpenAsync();
エラーの代表例と対処の対応表
| エラーの抜粋 | 原因 | 対処 |
|---|---|---|
| The certificate chain was issued by an authority that is not trusted. | 自己署名または未知の CA による証明書 | 正式 CA のサーバー証明書に置換。暫定なら TrustServerCertificate=true を開発限定で使用。 |
| The target principal name is incorrect. | 接続先名と証明書の CN/SAN が不一致(IP で接続、別名使用など) | FQDN で接続/DNS を修正/HostNameInCertificate を設定。 |
| Pre-login handshake error | TLS ハンドシェイク失敗(古いプロトコルや暗号スイート) | OS/SQL Server の TLS 設定を更新。最新パッチ適用。 |
本番での正攻法:SQL Server に正式証明書を配備する
企業内 CA や公的 CA で発行したサーバー証明書を SQL Server に割り当てます。ポイントは「名前の一致」と「鍵の扱い」です。
要件
- 鍵長 2048bit 以上、Key Usage = Digital Signature / Key Encipherment。
- EKU に Server Authentication (1.3.6.1.5.5.7.3.1)。
- CN または SAN に 接続で使用する FQDN(例:
prod-sql.example.com)。 - 秘密鍵はコンピューター アカウントに所有権。SQL Server サービス アカウントに読み取り権限。
Windows(オンプレ/VM)の手順概要
- 証明書を「ローカル コンピューター → 個人(Personal)」ストアへインポート(秘密鍵付き)。
- SQL Server 構成マネージャー → SQL Server ネットワークの構成 → プロトコル → 証明書 タブで割り当て。
- 必要なら「強制暗号化(Force Encryption)= 有効」にし、SQL Server サービスを再起動。
SELECT encrypt_option FROM sys.dm_exec_connections WHERE session_id = @@SPID;で暗号化状態を確認。
Linux/コンテナでのポイント
- サーバー秘密鍵(PEM)と証明書チェーン(PEM)を SQL Server が参照するパスへ配置し、権限を適切に設定。
- Docker では証明書をボリュームでマウント。開発用は
TrustServerCertificate=trueを併用して構築の複雑さを抑える。
開発・CI の現実解:安全性と利便性の落としどころ
ローカル開発や短命の CI データベースに正式証明書を配るのはコストが高い場面が多いでしょう。次の方針が実務的です。
- ローカル/CI:
Encrypt=true;TrustServerCertificate=true。接続先は原則localhost(または開発用 DNS)に限定。 - 機微データを扱う検証環境:本番同等の証明書を導入して
TrustServerCertificate=falseを維持。 - 接続先省略や IP 指定を避ける:証明書の名前一致に失敗しやすい。
名前不一致に強い設定:HostNameInCertificate の活用
DNS エイリアスや可用性グループのリスナー名を使う場合、証明書の CN/SAN と接続先名が一致するように設計するのが原則です。どうしても一致しない事情があるときは、接続文字列に HostNameInCertificate を付けて「証明書にはこの名前が入っているはず」を明示できます。
Server=10.0.0.12;Database=AppDb;Encrypt=true;
HostNameInCertificate=prod-sql.example.com;TrustServerCertificate=false
ただし、恒久対策は DNS と証明書の正規化です。暫定利用に留めましょう。
Azure SQL / マネージド DB を使う場合
- 管理サービスは既に信頼された証明書を配備済みのため、原則
Encrypt=trueのままで問題ありません。 - ファイアウォールやプライベート エンドポイントを併用し、IP 接続ではなく FQDN 接続に統一します。
EF Core の移行で見落としがちな差分
- ドライバーの乗り換え:
System.Data.SqlClientとMicrosoft.Data.SqlClientは別物。EF Core 7/8 は後者を使用。 - リトライとタイムアウト:暗号化切替直後はネットワーク負荷やスキャンの影響で遅延が出ることも。
EnableRetryOnFailureとCommandTimeoutを設計に入れる。 - 接続プール:設定変更後はアプリのリサイクルや再起動でプールをクリア。
セキュリティ観点の推奨事項(チェックリスト)
- 本番は
Encrypt=true固定、TrustServerCertificate=false。 - 証明書の CN/SAN と接続 FQDN の厳密一致を確認(IP 接続を避ける)。
- サーバー証明書の 有効期限監視と 自動更新(ACME/企業内 CA)を整備。
- アプリ設定は 環境ごとに分離(
appsettings.Development.json/.Production.json)。 - ログに 接続文字列の資格情報を書き出さない(PII マスク)。
運用テスト:暗号化の有効性を確認する
T-SQL で現在セッションを確認
SELECT session_id, encrypt_option
FROM sys.dm_exec_connections
WHERE session_id = @@SPID;
-- encrypt_option が TRUE なら暗号化済み
アプリ側での簡易確認
接続が確立できない場合は例外メッセージの先頭数行をログに残しておくと原因特定が早くなります(ただし秘密情報はマスク)。
Docker Compose を使った開発テンプレート(最小構成)
開発用途として、証明書配布の手間を省きつつ暗号化を保つ例です。
services:
sql:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=Your_strong_password_123
ports:
- "1433:1433"
web:
build: .
environment:
- ConnectionStrings__Default=Server=localhost,1433;Database=AppDb;
User ID=sa;Password=Your_strong_password_123;
Encrypt=true;TrustServerCertificate=true
この場合、通信は暗号化されますが証明書の真正性は検証しません。本番構成では必ず正式証明書に切り替えてください。
移行計画の作り方:ゼロダウンタイムを狙う手順
- 現行の接続文字列を棚卸しし、
EncryptとTrustServerCertificateの有無を洗い出し。 - 本番 SQL Server に正式証明書を先行配備(Force Encryption はまだ無効)。
- アプリ側で
Encrypt=trueを有効にして段階リリース。動作ログで証明書エラーの無いことを確認。 - 最後に SQL Server 側の Force Encryption を有効化(必要な場合)。
Q&A(現場でよく聞かれること)
Q. とりあえず Encrypt=false に戻すのはダメ?
A. 緊急避難としては有効ですが、平文通信になり盗聴のリスクがあります。恒久対策は正式証明書の導入です。
Q. TrustServerCertificate=true はどこまで許される?
A. 開発・CI まで。本番や機微データを扱う環境では禁止を推奨します。
Q. IP アドレスで接続しても大丈夫?
A. 証明書は通常 FQDN ベースで発行されるため、IP では名前不一致になりやすいです。FQDN で接続しましょう。
Q. Always On 可用性グループ/リスナー名は?
A. 証明書の SAN にリスナー名を含め、アプリもリスナー名(FQDN)で接続します。
まとめ
.NET 8/EF Core 7 以降では Encrypt=true が既定になりました。アップグレード後の証明書エラーは「バグ」ではなく「正しい保護」が働いた結果です。短期的に従来動作へ戻す方法(Encrypt=false)もありますが、推奨される道は「正式証明書を導入し、Encrypt=true を維持する」こと。開発では TrustServerCertificate=true を活用して利便性を確保しつつ、ステージング以降は本番同等の暗号化・検証を適用する――この二段構えが、セキュリティと生産性の両立に最も効きます。
付録:すぐに使える接続文字列スニペット集
| 用途 | スニペット |
|---|---|
| ローカル開発(Windows 認証) | Server=(localdb)\\MSSQLLocalDB;Database=DevDb;Encrypt=true;TrustServerCertificate=true;Trusted_Connection=True |
| ローカル開発(SQL 認証) | Server=localhost;Database=DevDb;User ID=sa;Password=***;Encrypt=true;TrustServerCertificate=true |
| オンプレ本番(正式証明書) | Server=prod-sql.example.com;Database=AppDb;Encrypt=true;TrustServerCertificate=false;Integrated Security=true |
| 名前不一致が避けられない暫定 | Server=10.0.0.12;Database=AppDb;Encrypt=true;HostNameInCertificate=prod-sql.example.com |
付録:トラブルシューティング・フロー
- 接続文字列に
Encryptが無ければ 明示追加(trueかfalse)。 Encrypt=trueで失敗したらメッセージに「chain」「principal name」等の文字列が無いか確認。- 「chain」系なら信頼されていない証明書 → 正式証明書に置換 or 開発限定で
TrustServerCertificate=true。 - 「principal name」系なら名前不一致 → FQDN で接続/DNS 修正/
HostNameInCertificate。 - 改善しなければ SQL Server の ERRORLOG と OS のイベントログを確認。TLS のバージョン/暗号スイート設定を見直し。
最後に:判断の基準
- 可搬性:FQDN と正規の証明書に揃えるほど移行や DR が楽。
- 最小権限:証明書の秘密鍵権限は SQL Server サービス アカウントのみに限定。
- 監査性:設定変更・証明書更新はチケット化し、満了前に自動アラート。
これらを押さえておけば、.NET 8 への移行後もエラーに足を取られず、安全な暗号化通信を当たり前の前提として運用できます。

コメント