😥

Powershell:Invoke-WebRequestに失敗する場合の対処方法(TLS1.2有効化)

2021/08/21に公開

こんにちは

AWS WorkspaceからSlackに通知したいことがあると思います。
WindowsからWebhookを叩く際に、PowershellのInvoke-WebRequestを実行すると思います。その際に以下のようなエラーが出ると場合の対処方法について解説します。

Invoke-WebRequest : 要求は中止されました: SSL/TLS のセキュリティで保護されているチャネルを作成できませんでした
Invoke-WebRequest : 接続が切断されました: 送信時に、予期しないエラーが発生しました

対処方法

以下のコマンドを実行して、TLS1.2を有効化することで回避する可能性があります。

> [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

前提条件

クライアント

  • Windows OS全般

サイト(Slack)

2021/08/21時点では、Slack は、Transport Layer Security(TLS)のバージョン 1.2 をサポートしています。
https://slack.com/intl/ja-jp/help/articles/115002037526-Slack-を利用するための最低システム要件

そのため、TSL1.2でリクエストをする必要性があります。

対処方法

クライアントのTSLバージョンを確認する

クライアントで有効化しているTSLのバージョンを確認するには以下のコマンドを実行します

> [Net.ServicePointManager]::SecurityProtocol
Ssl3,Tsl

このケースでは、クライアントがTSL1.0、サイトがTSL1.2をサポートなので、リクエストを処理できません

利用可能な接続方式を確認する

以下のコマンドで、実行環境で利用可能な接続方式を確認することができます

> [enum]::GetNames([Net.SecurityProtocolType])
SystemDefault
Ssl3
Tls
Tls11
Tls12
Tls13

TLS1.2が利用可能なのを確認できました

一時的にTSL1.2を有効化する

以下のコマンドで、一時的にTSL1.2を有効化することができます

> [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

確認し、TSL1.2が有効化することを確認します

> [Net.ServicePointManager]::SecurityProtocol
Tls12

これで、クライアント、サイトともにTSL1.2でしゃべるので、当初の Invoke-WebRequest コマンドを実行してください

Tips

今回の記載から脱線してしまうTpisをまとめました

1. TSLバージョンを複数指定したい

以下のコマンドで、複数の接続方式を有効化することができます
(今回の例では、TLS1.3とTLS1.2を有効化しています)

> [System.Net.ServicePointManager]::SecurityProtocol = @([System.Net.SecurityProtocolType]::Tls13,[System.Net.SecurityProtocolType]::Tls12)
Tls13,Tls12
2. PowerShellを起動したら、自動的にTLS1.2を有効化したい

今回記載した方法は、PowerShellを起動する度に、TLS1.2を有効化するコマンドを入力する必要があるため、少々面倒だと思います

そこで、PowerShellを起動したら、自動的にTLS1.2を有効化するように設定します
(bashでいう.bash_profile のようなものを設定します。レジストリからも設定できるようですが、あまりいじりたくないので)

下記コマンドで PowerShell のプロファイルの場所を確認します

> $profile
C:\Users\xxxxxx\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

コマンドの実行結果より、C:\Users\xxxxxx\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 をテキストエディタで開きます

下記を追記してファイルを保存します

[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;

新たにPowerShellを起動し、以下の実行結果が Tls12 と表示されれば設定完了です

> [Net.ServicePointManager]::SecurityProtocol
Tls12

これで、毎回TLSバージョン指定する必要がなくなりました

補足

他サイトの場合で同様の事象が発生し、TSLバージョンでも再発する場合、以下の対処で回避する可能性があります

1. サイトがBASIC認証をかけている
  • 以下のようにID、パスワードをいれてあげます。
$USER = "username"
$PASS = "password"
$secpasswd = ConvertTo-SecureString $PASS -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($USER, $secpasswd)
2. サイト側が自己証明書をつかっている
  • いわゆる、オレオレ証明書を利用しているバターンとなります
  • 以下のスプリクトを追加してあげるとうまくいきました
    • httpsの場合、サーバー証明書をチェックしているようで、 CertificatePolicyCheckValidationResultメソッドを無条件でTrueを返しているようです
add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

参考文献

https://docs.microsoft.com/ja-jp/dotnet/api/system.net.securityprotocoltype?view=net-5.0

https://ssl.sakura.ad.jp/column/ssl-browser-error/

https://tech.guitarrapc.com/entry/2013/09/23/164357

Discussion