TLS 1.0/1.1 を止めた、SchUseStrongCrypto を有効にした、暗号スイートを絞った。その直後に旧アプリだけ落ち、System ログに Schannel 36871 が並ぶ――このケースで最初に押さえるべき結論は、36871 は原因名ではなく、TLS 資格情報の作成に失敗した結果を示すイベントだということです。まずは「そのアプリが Schannel を使っているか」「失敗が Client 側か Server 側か」「OS の TLS 設定変更か、.NET/WCF/WinHTTP の既定値差か」を切り分けると、かなり早く絞れます。Microsoft も、TLS 1.0/1.1 を無効化したときに失敗するアプリの診断イベントとして 36871 を案内しています。 (Microsoft Learn)
さらに重要なのは、Schannel のレジストリ設定は Schannel SSP にしか効かないことです。Java や OpenSSL 同梱アプリのように独自の TLS 実装を持つソフトなら、Schannel をいくら見直しても直らないことがあります。ここを最初に見誤ると、ログは増えるのに原因は見つかりません。 (Microsoft Learn)
この記事では、Schannel 36871 と TLS 強化で旧アプリが落ちるときの切り分けを、最短で原因に近づく順番で整理します。判断基準、よくある誤診、戻してよい設定と戻さないほうがよい設定まで、実務前提でまとめます。
Schannel 36871 を見たら、まず「どの層が壊れたか」を決める
実務では、次の整理でかなり当たりが付きます。これは Microsoft の Schannel、.NET、WinHTTP の仕様差を、運用者向けにまとめたものです。 (Microsoft Learn)
| 現象の出方 | 第一候補 | 先に見るもの |
|---|---|---|
| 複数の Windows 系アプリが同時に失敗 | OS の Schannel 設定、GPO、暗号スイート順序 | SCHANNEL\Protocols、TLS 関連 GPO、再起動の有無 |
| 特定の .NET / WCF アプリだけ失敗 | コードや構成が OS 既定値を上書き | ServicePointManager.SecurityProtocol、SslProtocols.Default、AppContext |
| 古い Windows 端末や古いサーバーからの通信だけ失敗 | WinHTTP / .NET 更新不足 | DefaultSecureProtocols、.NET 更新、Wow6432Node 側の設定 |
| Java / OpenSSL 系だけ失敗 | アプリ独自 TLS 実装 | ベンダー製ランタイム、JRE/OpenSSL の設定 |
36871 は「向き」を見ないと誤診しやすい
Microsoft の診断例では、36871 のメッセージは TLS <client/server> credential の形式で出ます。ここは単なる文言ではなく、どちらの役割で失敗したかを見る重要な手掛かりです。Schannel のプロトコル設定も Client と Server に分かれているため、サーバー上で動くアプリでも「外部 API に出ていく通信」が落ちているなら、見るべきは Server ではなく Client 側です。ここを逆に見るのが、いちばん多い遠回りです。 (Microsoft Learn)
レジストリ上では、HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols 配下でプロトコルを管理します。Microsoft は、Enabled=1 でシステム既定を上書きして有効化、Enabled=0 で無効化できることを案内していますが、同時に プロトコルを減らすと相互運用性が壊れ、資格情報取得に失敗する可能性があるとも明記しています。しかも変更は新しい資格情報ハンドル取得後に効くため、アプリやサービスの再起動が必要になることがあります。 (Microsoft Learn)
最短で原因に近づく切り分け手順
直前に変えたものを「OS」「フレームワーク」「アプリ」に分ける
最初にやるべきは、直前の変更を 1 枚に並べることです。具体的には次の 3 系統です。
- OS / Schannel 側
TLS 1.0/1.1 の無効化、暗号スイート順序の変更、TLS 関連 GPO、サーバー再起動 - フレームワーク側
.NET Framework 更新、SystemDefaultTlsVersionsやSchUseStrongCryptoの投入、AppContext 変更 - アプリ側
ベンダーアップデート、接続先変更、構成ファイル変更、証明書更新
この切り分けが大事なのは、設定が効くタイミングが同じではないからです。暗号スイート順序の変更は次回起動時に反映され、Schannel のプロトコル変更もアプリが資格情報ハンドルを取り直すまでは見えないことがあります。変更日だけでなく、再起動日とサービス再起動日まで並べると、かなり精度が上がります。 (Microsoft Learn)
Schannel ログは一時的に詳細化する
Schannel のイベント ログは、Windows 既定では 0x00000001(エラーのみ) です。必要なら EventLogging を上げて、警告や情報まで一時的に出すことができます。ただし、Microsoft は反映に再起動が必要だとしています。切り分け中だけ 0x3 か 0x7 に上げ、再現後に戻す運用が現実的です。 (Microsoft Learn)
reg add "HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL" `
/v EventLogging /t REG_DWORD /d 3 /f
ログを見たら、時刻、client/server、PID、失敗した相手先を 1 セットで控えます。PID が取れるなら、その時刻の実プロセス名と突き合わせてください。SYSTEM で動く常駐サービスは多いため、「PID が 4 だから OS が悪い」とは限りません。
暗号スイート制限を忘れない
TLS 1.2 を有効にしたのに落ちるときは、プロトコルではなく暗号スイートの不一致を疑うべき場面があります。Microsoft は、Windows のバージョンごとにサポートされる暗号スイートと優先順位が異なること、暗号スイートの管理は GPO・MDM・PowerShell で行うこと、既定の優先順位をレジストリで直接いじるのはサポートされないことを案内しています。 (Microsoft Learn)
現在の一覧は PowerShell ですぐ確認できます。Get-TlsCipherSuite は、コンピューターが使える TLS 暗号スイートの順序付き一覧を返します。暗号スイート順序の変更は再起動まで反映されないので、設定だけ見て「直したはず」と判断しないことが重要です。 (Microsoft Learn)
Get-TlsCipherSuite | Select-Object Name, Protocols
.NET / WCF は「実行環境」より「対象バージョン」と「明示設定」を疑う
.NET Framework 4.7 以降なら大丈夫 と考えるのは危険です。Microsoft によると、.NET Framework 4.7 以降では ServicePointManager.SecurityProtocol の既定値は SystemDefault で、OS の既定 TLS を継承します。ただし、既存接続は変わらず、新しい接続にしか効きません。しかも、アプリ側でこの値を明示設定すると、OS 既定値への追従を自分で壊してしまいます。 (Microsoft Learn)
特に見落としやすいのが、古い対象バージョンのアプリを新しい .NET 実行環境で動かしているケースです。Microsoft は、AppContext スイッチの既定値が「実行中の .NET」ではなく対象バージョンで変わることを説明しています。つまり、サーバーに新しい .NET が入っていても、アプリが古いターゲットのままだと、DontEnableSystemDefaultTlsVersions や WCF 関連スイッチが古い挙動のまま残ることがあります。さらに、コードでセキュリティ プロトコル値を指定すると、これらのスイッチは上書きされます。 (Microsoft Learn)
旧 .NET アプリで特に危ない書き方
Microsoft は、TLS バージョンのハードコードを避けるよう案内しています。どうしても明示指定を避けられない場合でも、TLS 1.2 か TLS 1.3 を推奨しています。逆に、SslProtocols.Default は要注意です。Microsoft はこれを使うと SSL 3.0 / TLS 1.0 を強制し、TLS 1.2 は使われないと明記しています。古いサンプルコードがそのまま残っている環境では、ここだけで落ちることがあります。 (Microsoft Learn)
検索すべき文字列は、少なくとも次のあたりです。
ServicePointManager.SecurityProtocol
SecurityProtocolType.Tls
SecurityProtocolType.Tls11
SecurityProtocolType.Tls12
SslProtocols.Default
SslProtocols.Tls
SslProtocols.Tls11
SslProtocols.Tls12
Switch.System.Net.DontEnableSchUseStrongCrypto
Switch.System.Net.DontEnableSystemDefaultTlsVersions
Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols
Switch.System.ServiceModel.DontEnableSystemDefaultTlsVersions
WCF は「NetTcp か」「メッセージ セキュリティか」で見る
WCF はさらに癖があります。Microsoft は、WCF が .NET Framework 4.7 で TLS 1.2 を既定サポートし、4.7.1 以降では OS 既定の TLS を使う構成に寄せられること、NetTcp では SslProtocols.None で OS 既定を使えることを説明しています。一方で、Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols=true のような設定が残っていると、メッセージ セキュリティ側が古い選択に寄ることがあります。WCF だけ落ちるなら、まずここを見ます。 (Microsoft Learn)
SchUseStrongCrypto は「良い設定」だが、古い相手は落ちうる
SchUseStrongCrypto を入れたのに旧アプリが落ちたとき、「設定ミス」と断定しないでください。Microsoft は、.NET Framework が SCH_USE_STRONG_CRYPTO を使うと、既知の弱い暗号アルゴリズム、暗号スイート、TLS/SSL バージョンを無効にするよう Schannel に指示すると説明しています。つまり、相手が弱い方式しか話せないと、正しく落ちます。これはバグではなく、強化の副作用です。 (Microsoft Learn)
レガシーな .NET アプリでは、レジストリ側の整備も確認してください。Microsoft は、SystemDefaultTlsVersions=1 と SchUseStrongCrypto=1 を v2.0.50727 と v4.0.30319、さらに 64bit OS 上の 32bit アプリ向けに Wow6432Node 側にも設定する例を示しています。32bit アプリなのに 64bit 側だけ見て「設定済み」と判断するのは、よくあるハマりどころです。 (Microsoft Learn)
古い OS / WinHTTP は別の落とし穴がある
古い Windows を含む環境では、WinHTTP の既定値差も無視できません。Microsoft は、Windows 8.1 / Server 2012 R2 / Windows 10 / Server 2016 以降は WinHTTP で TLS 1.2 をネイティブにサポートするとしつつ、Windows 7 や Windows Server 2012 などの旧版では、TLS 1.1/1.2 が WinHTTP の既定で有効ではないこと、更新プログラムと DefaultSecureProtocols 設定が必要になる場合があると案内しています。さらに、古いクライアント側の設定を有効にする前にサーバーで旧プロトコルを切ると、クライアントを孤立させる恐れがあるとも注意しています。 (Microsoft Learn)
ここで実務上の注意点があります。Microsoft の例に出てくる 0xAA0 は、移行用に SSL 3.0 / TLS 1.0 を残しつつ TLS 1.1 / 1.2 を追加する値です。つまり、障害回避には役立っても、TLS 強化の最終形ではありません。古い記事を見てこの値をそのまま入れると、「つながったけれど古い依存を温存しただけ」という状態になりやすいです。 (Microsoft Learn)
ここを見落とすと、いつまでも直らない
Server 側だけ見て Client 側を見ない
外部 API 呼び出し、SMTP 送信、外向き Web アクセスなど、サーバー上のアプリでも outbound 通信は Client 側です。Server サブキーだけ見直しても改善しません。 (Microsoft Learn)
Tls12 を書けば安心だと思う
今は動いても、将来また同じ問題を作ります。Microsoft はハードコード回避を推奨しており、.NET Framework 4.7+ では OS 既定値を使う方向が基本です。どうしても明示指定が必要な場面を除き、SystemDefault や OS 既定に寄せるほうが保守しやすくなります。 (Microsoft Learn)
変更後にプロセスを再起動していない
ServicePointManager.SecurityProtocol は新しい接続にしか効かず、Schannel のプロトコル設定もアプリが資格情報ハンドルを取り直すまで見えない場合があります。設定変更だけで結果を判定すると、誤診しやすくなります。 (Microsoft Learn)
暗号スイートをレジストリ直書きで調整する
Microsoft は、既定の優先順位をレジストリで直接更新する方法をサポートしていません。暗号スイートの管理は GPO、MDM、PowerShell で行うべきです。 (Microsoft Learn)
一時対処は「どこまで戻すか」を決めてからやる
障害対応では一時回避が必要になることがありますが、戻し方の粒度で安全性が大きく変わります。
| 優先度 | 対処 | 向くケース | 注意点 |
|---|---|---|---|
| 高 | アプリ更新、.NET 対象バージョン見直し、コード修正 | ベンダー更新や再ビルドが可能 | 根本解決。再発しにくい |
| 高 | .NET を OS 既定 TLS 利用へ寄せる | .NET / WCF だけ落ちる | AppContext や明示設定の確認が必要 |
| 中 | 必要な TLS 1.2/1.3 暗号スイートだけ戻す | プロトコルは合うが handshake 失敗 | GPO/PowerShell 管理、再起動前提 |
| 中 | エンドポイントを分離する | IIS / HTTP.sys で新旧クライアント混在 | 実装できるスタックが限られる |
| 低 | TLS 1.0/1.1 を一時再有効化する | 事業継続優先で今すぐ止血が必要 | 最後の手段。期限を切る |
Microsoft は、TLS 1.0/1.1 の再有効化を最後の手段かつ一時的な対策として扱うべきだと案内しています。一方で、IIS / HTTP.sys 系では、証明書バインド単位で legacy TLS を抑止する仕組みがあり、同じホスト上に「TLS 1.2+ 専用」と「一時的なレガシー用」を分ける考え方も紹介されています。全体を戻す前に、こうした粒度の細かい逃がし方ができないかを検討する価値があります。 (Microsoft Learn)
現場でそのまま使える確認コマンド
まずは Schannel イベントを時系列で拾います。
Get-WinEvent -FilterHashtable @{
LogName='System'
ProviderName='Schannel'
StartTime=(Get-Date).AddHours(-6)
} | Select-Object TimeCreated, Id, LevelDisplayName, Message
次に、使える暗号スイートを確認します。Get-TlsCipherSuite は順序付き一覧を返すので、GPO 変更後の差分確認に向いています。 (Microsoft Learn)
Get-TlsCipherSuite | Select-Object Name, Protocols
Schannel のプロトコル設定は、Client と Server を分けて見ます。 (Microsoft Learn)
reg query "HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols" /s
レガシー .NET なら、64bit / 32bit の両方を確認します。Microsoft は Wow6432Node 側の確認も案内しています。 (Microsoft Learn)
reg query "HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319"
reg query "HKLM\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319"
ソースコードや構成ファイルでは、前述の文字列検索をかけてください。.NET の TLS 問題は、コード 1 行で OS 既定値を上書きしていることが想像以上に多いです。
迷ったときの判断基準
Schannel 36871 が出たときは、「TLS が壊れた」のではなく、「どの層が TLS を選んだか」が壊れたと考えると整理しやすくなります。OS 全体で同時多発なら Schannel や暗号スイート、特定の .NET/WCF だけならコードや AppContext、古い OS だけなら WinHTTP や更新不足、Java/OpenSSL 系なら Schannel 以外を優先して見る――この順番が、いちばんムダが少ない切り分けです。 (Microsoft Learn)
最後にやるべきことは 3 つです。イベントの client/server と PID を確定すること、直前の TLS 強化内容を OS・フレームワーク・アプリに分けること、そして Schannel を使うアプリかどうか を最初に見切ることです。ここまで押さえれば、TLS 1.0/1.1 を慌てて全戻しする前に、かなりの確率で「どこを直せばよいか」が見えてきます。再有効化は、期限付きの一時対応としてだけ使うのが安全です。 (Microsoft Learn)

コメント