Erro de HTTPS do PowerShell v3 Invoke-WebRequest

126

Usando Invoke-WebRequest e Invoke-RestMethod do Powershell v3, usei com êxito o método POST para postar um arquivo json em um site https.

O comando que estou usando é

 $cert=New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("cert.crt")
 Invoke-WebRequest -Uri https://IPADDRESS/resource -Credential $cred -certificate $cert -Body $json -ContentType application/json -Method POST

No entanto, quando tento usar o método GET, como:

 Invoke-WebRequest -Uri https://IPADDRESS/resource -Credential $cred -certificate $cert -Method GET

O seguinte erro é retornado

 Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
 At line:8 char:11
 + $output = Invoke-RestMethod -Uri https://IPADDRESS/resource -Credential $cred
 +           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest)      [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Tentei usar o código a seguir para ignorar o certificado SSL, mas não tenho certeza se ele está realmente fazendo alguma coisa.

 [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

Alguém pode fornecer alguma orientação sobre o que pode estar errado aqui e como corrigi-lo?

obrigado

floyd
fonte
Então, qual você está usando? Invoke-RestMethodou Invoke-WebRequest?
svick
Invoke-WebRequest. Eu o uso porque ele retorna os cabeçalhos de solicitação / resposne, ao contrário de Invoke-RestMethod. No entanto, tentei Invoke-RestMethod, que também usa parâmetros idênticos.
Floyd
Pelo que vale a pena, a coisa ServerValidationCallback é quase certamente um arenque vermelho, já que o erro que você deve receber quando tem um problema de validação SSL deve dizer: Invoke-WebRequest : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. Você pode tentar explorar $ Error [0] .Exception.InnerException para obter mais informações .. .
Jaykul

Respostas:

179

Esta solução alternativa funcionou para mim: http://connect.microsoft.com/PowerShell/feedback/details/419466/new-webserviceproxy-needs-force-parameter-to-ignore-ssl-errors

Basicamente, no seu script do PowerShell:

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

$result = Invoke-WebRequest -Uri "https://IpAddress/resource"
Lee Grissom
fonte
9
Observe que esta resposta está correta; no entanto, o argumento apresentado em outra resposta ( stackoverflow.com/a/25163476/68432 ) também é válido. Esta solução não funcionará se você tiver feito "[System.Net.ServicePointManager] :: ServerCertificateValidationCallback = {$ true}" anteriormente.
Paul Suart
Você precisa adicionar a verificação de condição Tipo como por resposta Arthur Strutzenberg abaixo ou você receberá um erro dizendo que o tipo já existe
Ralph Willgoss
Existe um risco de segurança para usar isso na produção?
22418 Amjad
13
Cinco anos depois, essa ainda é a solução para o PowerShell 5.1 (.NET Framework completo). Para o PowerShell Core, existe um -SkipCertificateCheckagora.
precisa saber é o seguinte
MS retirou o Connect, esse link é inválido. Existe outro link?
Mark Heath
71

A resposta de Lee é ótima, mas também tive problemas com os protocolos suportados pelo servidor da web.
Depois de adicionar também as seguintes linhas, eu poderia obter a solicitação https. Conforme indicado nesta resposta https://stackoverflow.com/a/36266735

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

Minha solução completa com o código de Lee.

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;
    }
}
"@
$AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
AndOs
fonte
você encontrou uma solução melhor, porque se você tiver 40 scripts, será necessário adicioná-lo a cada um. Parece não fazer nenhum sentido. Btw, obrigado pela resposta
Ender
1
A resposta de Lee não funcionou para mim. Eu tive que adicionar os bits que você referenciou e funcionou!
Pat K #
Muito obrigado, especificando os protocolos ajudaram a resolver o problema
Alex
1
Obrigado obrigado obrigado por me mostrar a SecurityProtocolpropriedade estática global. Cristo, acabei de perder DAYS ao verificar certificados, relações de confiança, rede, rotas, permissões e muitas outras coisas, tentando resolver um endpoint does not responderro vago ao acessar um servidor específico via https (todos os outros funcionam), só porque esse maldito PowerShell 5.1 padrões para SSL3, TLS e isso só BLOCOS MALDITO TLS11 e TLS12 incumprimento por deus o quanto eu odeio essa porcaria que eu deveria ter escrito esse script em C # / ruby / C ++ ou qualquer outra coisa que não seja powershell
quetzalcoatl
1
@ StanTastic: Eu acho que é impossível alterar permanentemente os padrões. Eu acho que está codificado no código fonte do ServicePointManager. Eu nunca verifiquei, então talvez haja alguma maneira.
quetzalcoatl
10

Você tentou usar System.Net.WebClient?

$url = 'https://IPADDRESS/resource'
$wc = New-Object System.Net.WebClient
$wc.Credentials = New-Object System.Net.NetworkCredential("username","password")
$wc.DownloadString($url)
Sunny Chakraborty
fonte
Sunny, recebo o seguinte ao usar esse código: Exceção ao chamar "DownloadString" com o argumento "1": "O servidor remoto retornou um erro: (406) Não Aceitável." Na linha: 4 char: 1 + $ wc.DownloadString ($ url) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ], MethodInvocationException + FullyQualifiedErrorId: WebException
floyd
Com base na documentação da API do im serviço REST usando 406 indica que "a aceitar cabeçalho incluído no pedido não permitir que um XML ou JSON resposta"
floyd
Quais tipos de resposta são permitidos se respostas XML / JSON não são permitidas?
Sunny Chakraborty
Este é um serviço da web personalizado que você está usando? Existe alguma documentação disponível publicamente para a API REST?
Sunny Chakraborty
É um sistema de emissão de bilhetes chamado EM7. Não acredito que eles tenham documentos públicos. O serviço aceita resposta JSON / XML (funciona bem se eu usar cURL). Acredito que o erro esteja indicando que o System.Net.WebClient não está?
Floyd
9

Uma implementação alternativa em puro (sem Add-Type de fonte):

#requires -Version 5
#requires -PSEdition Desktop

class TrustAllCertsPolicy : System.Net.ICertificatePolicy {
    [bool] CheckValidationResult([System.Net.ServicePoint] $a,
                                 [System.Security.Cryptography.X509Certificates.X509Certificate] $b,
                                 [System.Net.WebRequest] $c,
                                 [int] $d) {
        return $true
    }
}
[System.Net.ServicePointManager]::CertificatePolicy = [TrustAllCertsPolicy]::new()
Maximilian Burszley
fonte
7

O seguinte funcionou para mim (e usa os meios não obsoletos mais recentes para interagir com a funcionalidade SSL Certs / retorno de chamada) e não tenta carregar o mesmo código várias vezes na mesma sessão do PowerShell:

if (-not ([System.Management.Automation.PSTypeName]'ServerCertificateValidationCallback').Type)
{
$certCallback=@"
    using System;
    using System.Net;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    public class ServerCertificateValidationCallback
    {
        public static void Ignore()
        {
            if(ServicePointManager.ServerCertificateValidationCallback ==null)
            {
                ServicePointManager.ServerCertificateValidationCallback += 
                    delegate
                    (
                        Object obj, 
                        X509Certificate certificate, 
                        X509Chain chain, 
                        SslPolicyErrors errors
                    )
                    {
                        return true;
                    };
            }
        }
    }
"@
    Add-Type $certCallback
 }
[ServerCertificateValidationCallback]::Ignore();

Isso foi adaptado do seguinte artigo https://d-fens.ch/2013/12/20/nobrainer-ssl-connection-error-when-using-powershell/

Arthur Strutzenberg
fonte
5

Descobri que quando usei a função this callback para ignorar certificados SSL [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

Eu sempre recebi a mensagem de erro Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send.que soa como os resultados que você está tendo.

Encontrei este post no fórum que me levou à função abaixo. Eu corro isso uma vez dentro do escopo do meu outro código e funciona para mim.

function Ignore-SSLCertificates
{
    $Provider = New-Object Microsoft.CSharp.CSharpCodeProvider
    $Compiler = $Provider.CreateCompiler()
    $Params = New-Object System.CodeDom.Compiler.CompilerParameters
    $Params.GenerateExecutable = $false
    $Params.GenerateInMemory = $true
    $Params.IncludeDebugInformation = $false
    $Params.ReferencedAssemblies.Add("System.DLL") > $null
    $TASource=@'
        namespace Local.ToolkitExtensions.Net.CertificatePolicy
        {
            public class TrustAll : System.Net.ICertificatePolicy
            {
                public bool CheckValidationResult(System.Net.ServicePoint sp,System.Security.Cryptography.X509Certificates.X509Certificate cert, System.Net.WebRequest req, int problem)
                {
                    return true;
                }
            }
        }
'@ 
    $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
    $TAAssembly=$TAResults.CompiledAssembly
    ## We create an instance of TrustAll and attach it to the ServicePointManager
    $TrustAll = $TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
    [System.Net.ServicePointManager]::CertificatePolicy = $TrustAll
}

Aaron D
fonte
1

Tentei procurar documentação na API REST EM7 OpenSource. Sem sorte até agora.

http://blog.sciencelogic.com/sciencelogic-em7-the-next-generation/05/2011

Fala-se muito sobre a API REST OpenSource, mas nenhum link para a API real ou para qualquer documentação. Talvez eu estivesse impaciente.

Aqui estão algumas coisas que você pode experimentar

$a = Invoke-RestMethod -Uri https://IPADDRESS/resource -Credential $cred -certificate $cert 
$a.Results | ConvertFrom-Json

Tente isso para ver se é possível filtrar as colunas que você está recebendo da API

$a.Results | ft

ou você pode tentar usar isso também

$b = Invoke-WebRequest -Uri https://IPADDRESS/resource -Credential $cred -certificate $cert 
$b.Content | ConvertFrom-Json

Cabeçalhos de estilo de ondulação

$b.Headers

Testei o IRM / IWR com a API JSON do twitter.

$a = Invoke-RestMethod http://search.twitter.com/search.json?q=PowerShell 

Espero que isto ajude.

Sunny Chakraborty
fonte
Obrigado por toda a sua ajuda. No entanto, o primeiro comando $ a = Invoke-RestMethod (...) é o que atualmente não funciona para mim. Funciona bem para um site HTTP, mas quando você introduz o HTTPS, o EM7 o faz retornar o erro descrito. Isso é para Invoke-RestMethod e Invoke-WebRequest. Estou apenas usando um cmdlet Invoke-Command e executando curl.
floyd
1

Invoke-WebRequest "DomainName" -SkipCertificateCheck

Você pode usar o parâmetro -SkipCertificateCheck para obter isso como um comando de uma linha (ESTE PARÂMETRO É SOMENTE SUPORTADO NA PSEDIÇÃO PRINCIPAL)

Amar Helloween
fonte
0
  1. Execute este comando

New-SelfSignedCertificate -certstorelocation cert: \ localmachine \ my -dnsname {your-site-hostname}

no powershell usando direitos de administrador , isso gerará todos os certificados no diretório pessoal

  1. Para se livrar do erro de privacidade, selecione esses certificados, clique com o botão direito do mouse em → Copiar. E cole em Autoridade de certificação raiz confiável / Certificados.
  2. O último passo é selecionar as ligações corretas no IIS. Vá para o site do IIS, selecione Ligações, marque a caixa de seleção SNI e defina os certificados individuais para cada site.

Verifique se o nome do host do site e o certificado dns-name devem corresponder exatamente

Mohit Dharmadhikari
fonte
0

Essas configurações do registro afetam o .NET Framework 4+ e, portanto, o PowerShell. Defina-os e reinicie as sessões do PowerShell para usar o TLS mais recente, sem necessidade de reinicialização.

Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord 

Consulte https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#schusestrongcrypto

Jeremy Cook
fonte
Para qualquer pessoa que veja esta resposta, nossa experiência é que esse patch do registro exige, de fato, uma reinicialização para garantir a funcionalidade adequada. Ao tentar garantir uma conexão TLS 1.2 entre uma caixa do Windows executando um aplicativo .NET, o SSL 3 foi mostrado via rastreamento de rede para ser usado com esse valor do registro, mas antes de uma reinicialização; O TLS 1.2 foi chamado apenas após uma reinicialização.
David W
-1

Se você executar isso como administrador, esse erro deverá desaparecer

Autonômico
fonte