无法从证书未经验证的服务器下载文件

Unable to download files from a server with unverified certificate

提问人:M-- 提问时间:11/16/2023 最后编辑:M-- 更新时间:11/16/2023 访问量:50

问:

我正在尝试从没有经过验证的 SSL 证书的网站下载一些文件。我使用此处解释的方法忽略了SSL警告:使用powershell downloadstring忽略SSL警告

###################### Download ###################### 
## download zipped files from WebPage/download (No Valid SSL Certificate)
$myDownloadUrl = 'www.SomeWebPage.com/Download/MyFiles.zip'

## installation folder (always under %appdata%\Company\MyFolder)
$myZipFile = "MyFiles.zip"
$installdir = "\Company\MyFolder\"
$myInstallDir = -join @($env:APPDATA, $installdir)
$myFilePath = -join@($myInstallDir, $myZipFile)

## make sure the folder exists
New-Item -ItemType Directory -Force -Path $myInstallDir

## Skip certificate
$code= @"
        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;
            }
        }
"@
Add-Type -TypeDefinition $code -Language CSharp
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

echo ">> Downloading the Files..."
Invoke-WebRequest -Uri $myDownloadUrl -OutFile $myFilePath
Start-Sleep -s 2

在大多数情况下,这都按预期工作。但是,有时它会返回错误:

ERROR: Unable to  read data from the transport connection: An existing connection was forcibly closed by the remote host.
ERROR: Exception calling ".ctor" with "3" argument(s): "End of Central Directory record could not be found."

我尝试将这样的东西添加到我的脚本中,但问题仍然存在。我仍然可能会遇到一次错误,但另一次不会。(来源:Invoke-WebRequest SSL 失败?)

$AllProtocols = [System.Net.SecurityProtocolType]'Tls,Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols

在继续操作之前,我是否可以执行 try-catch 例程以确保文件已正确下载?

下面是该服务器的概述摘要

PowerShell SSL 证书 Invoke-WebRequest

评论


答:

1赞 suchislife 11/16/2023 #1

此问题可能是由于 PowerShell 脚本使用的安全协议所致。在处理使用过时或未经验证的SSL证书的网站时,指定安全协议会有所帮助。您建议的指定所有协议(、)的解决方案是一个很好的方法。但是,重要的是要注意 AND 已过时且安全性较低,通常不鼓励使用它们。Ssl2Ssl3TlsTls11Tls12Ssl2Ssl3

下面是一个包含安全协议设置的调整脚本:

# Define the URL and installation directory
$myDownloadUrl = 'https://www.SomeWebPage.com/Download/MyFiles.zip'
$myZipFile = "MyFiles.zip"
$installdir = "\Company\MyFolder\"
$myInstallDir = Join-Path $env:APPDATA $installdir
$myFilePath = Join-Path $myInstallDir $myZipFile

# Ensure the installation directory exists
New-Item -ItemType Directory -Force -Path $myInstallDir

# Trust all certificates
Add-Type -TypeDefinition @"
    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;
        }
    }
"@ -Language CSharp
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

# Set security protocols (excluding outdated protocols for better security)
$SecureProtocols = [System.Net.SecurityProtocolType]'Tls,Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $SecureProtocols

# Download the file
Write-Host ">> Downloading the Files..."
Invoke-WebRequest -Uri $myDownloadUrl -OutFile $myFilePath
Start-Sleep -Seconds 2
  • 安全协议:该脚本现在将安全协议显式设置为 Tls、Tls11 和 Tls12。这确保了与大多数 服务器,同时保持更高的安全性。
  • 路径构建:使用 Join-Path 进行更好的路径构建。
  • 信任策略:该脚本保留信任策略以接受未经验证的 SSL 证书。

评论

0赞 M-- 11/16/2023
这似乎不是问题的根源。无论有没有这些行,我都会收到错误。实际上,我能够在我的机器上复制错误。这个问题似乎有些随机,因为它可能会发生一次,而不是下次我运行脚本时发生:/
0赞 suchislife 11/16/2023
你可能会认为在 Let's Encrypt 推出后,人们不会仍然托管这样的网站了,呵呵......去想想。
0赞 M-- 11/16/2023 #2

正如我上面所解释的,下载文件有时没有问题,有时会失败。因此,我添加了一个 try-catch 以继续尝试,直到成功。这基于以下线程: 捕获 FULL 异常消息

我不确定是什么原因导致了这个问题,并认为这是一种解决方法而不是解决方案。

## set ErrorActionPreference to stop
$ErrorActionPreferenceBak = $ErrorActionPreference
$ErrorActionPreference    = 'Stop'

While($True){
    try{
        ## downloading the files
        Invoke-WebRequest -Uri $myDownloadUrl -OutFile $myFilePath
        break
    }
    catch{
        Write-Host "Something failed while downloading the files; trying again"
        Start-Sleep -s 1
    }
    finally{
        ## reset ErrorActionPreference
        $ErrorActionPreference = $ErrorActionPreferenceBak
    }
}