Powershell v3 Invoke-WebRequest Error de HTTPS


126

Utilizando Invoke-WebRequest e Invoke-RestMethod de Powershell v3, he utilizado con éxito el método POST para publicar un archivo json en un sitio web https.

El comando que estoy usando es

 $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

Sin embargo, cuando intento usar el método GET como:

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

Se devuelve el siguiente error

 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

Intenté usar el siguiente código para ignorar el certificado SSL, pero no estoy seguro de si realmente está haciendo algo.

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

¿Alguien puede proporcionar alguna guía sobre lo que podría estar mal aquí y cómo solucionarlo?

Gracias


Entonces, ¿cuál estás usando? Invoke-RestMethodo Invoke-WebRequest?
svick

Invoke-WebRequest. Lo uso ya que devuelve los encabezados de solicitud / respuesta a diferencia de Invoke-RestMethod. Sin embargo, he intentado Invoke-RestMethod que también toma parámetros idénticos.
floyd

Para lo que vale, lo de ServerValidationCallback es casi seguro que es una pista falsa, ya que el error que debe obtener cuando tiene un problema de validación SSL debe decir: debe Invoke-WebRequest : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. intentar explorar $ Error [0] .Exception.InnerException para obtener más información. .
Jaykul

Respuestas:


179

Esta solución me funcionó: http://connect.microsoft.com/PowerShell/feedback/details/419466/new-webserviceproxy-needs-force-parameter-to-ignore-ssl-errors

Básicamente, en su script de 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"

9
Tenga en cuenta que esta respuesta es correcta; sin embargo, el punto hecho en otra respuesta ( stackoverflow.com/a/25163476/68432 ) también es válido. Esta solución no funcionará si ya ha hecho "[System.Net.ServicePointManager] :: ServerCertificateValidationCallback = {$ true}" de antemano.
Paul Suart

Debe agregar la verificación de condición de Tipo según la respuesta de Arthur Strutzenberg a continuación o recibirá un error que dice que el tipo ya existe
Ralph Willgoss

¿Existe un riesgo de seguridad por usar esto en producción?
Amjad

13
5 años después, esa sigue siendo la solución para PowerShell 5.1 (.NET Framework completo). Para PowerShell Core hay un -SkipCertificateCheckahora.
evilSnobu

MS ha eliminado Connect, ese enlace no es válido. ¿Hay otro enlace?
Mark Heath

71

La respuesta de Lee es excelente, pero también tuve problemas con los protocolos que admitía el servidor web.
Después de agregar también las siguientes líneas, pude obtener la solicitud https. Como se señaló en esta respuesta https://stackoverflow.com/a/36266735

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

Mi solución completa con el 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

¿ha encontrado una mejor solución, porque si tiene 40 scripts, entonces debe agregarlos a cada uno? Parece que no tiene ningún sentido. Por cierto, gracias por la respuesta
Ender

1
La respuesta de Lee no funcionó para mí. ¡Tuve que agregar los bits a los que hizo referencia y FUNCIONÓ!
Pat K

Muchas gracias, la especificación de los protocolos ayudó a resolver el problema
Alex

1
Gracias, gracias, gracias por mostrarme la SecurityProtocolpropiedad estática global. Cristo, acabo de perder DÍAS al verificar certificados, fideicomisos, redes, rutas, permisos y un montón de otras cosas que intentan resolver endpoint does not responderrores vagos al acceder a un servidor específico a través de https (todos los demás funcionan), solo porque ese maldito PowerShell 5.1 por defecto es SSL3, TLS y SOLO BLOQUEA DIOSA TLS11 y TLS12 POR DEFECTO Dios, cuánto odio esta basura, debería haber escrito esa secuencia de comandos en C # / Ruby / C ++, o cualquier otra cosa que no sea powershell
quetzalcoatl

1
@StanTastic: Creo que es imposible cambiar permanentemente los valores predeterminados. Creo que está codificado en el código fuente de ServicePointManager. Sin embargo, nunca lo revisé, así que tal vez haya alguna manera.
quetzalcoatl

10

¿Intentaste 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, recibo lo siguiente cuando uso ese código: Excepción que llama a "DownloadString" con "1" argumento (s): "El servidor remoto devolvió un error: (406) No es aceptable". En la línea: 4 caracteres: 1 + $ wc.DownloadString ($ url) + ~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo: NotSpecified: (:) [ ], MethodInvocationException + FullyQualifiedErrorId: WebException
floyd

Según la documentación de API del servicio REST que estoy usando 406 indica "que el encabezado de aceptación incluido en la solicitud no permite una respuesta XML o JSON"
floyd

¿Qué tipos de respuesta están permitidos si las respuestas XML / JSON no están permitidas?
Sunny Chakraborty

¿Es este un servicio web personalizado que está utilizando? ¿Existe alguna documentación disponible públicamente para la API REST?
Sunny Chakraborty

Es un sistema de tickets llamado EM7. No creo que tengan documentos públicos. El servicio acepta la respuesta JSON / XML (funciona bien si uso cURL). Creo que el error indica que System.Net.WebClient no lo es.
floyd

9

Una implementación alternativa en puro (sin Add-Typede fuente):

#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()

7

Lo siguiente funcionó para mí (y utiliza los últimos medios no obsoletos para interactuar con la funcionalidad SSL Certs / callback), y no intenta cargar el mismo código varias veces dentro de la misma sesión de 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();

Esto fue adaptado del siguiente artículo https://d-fens.ch/2013/12/20/nobrainer-ssl-connection-error-when-using-powershell/


5

Descubrí que cuando utilicé esta función de devolución de llamada para ignorar los certificados SSL [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

Siempre recibí el mensaje de error Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send. que suena como los resultados que está teniendo.

Encontré esta publicación en el foro que me lleva a la función a continuación. Ejecuté esto una vez dentro del alcance de mi otro código y funciona para mí.

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
}


1

Intenté buscar documentación en la API REST OpenSource de EM7. Sin suerte hasta ahora.

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

Se habla mucho sobre OpenSource REST API, pero no hay enlace a la API real ni a ninguna documentación. Quizás estaba impaciente.

Aquí hay algunas cosas que puedes probar

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

Pruebe esto para ver si puede filtrar las columnas que obtiene de la API

$a.Results | ft

o puedes intentar usar esto también

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

Encabezados de estilo rizo

$b.Headers

Probé el IRM / IWR con la API JSON de Twitter.

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

Espero que esto ayude.


Gracias por toda su colaboración. Sin embargo, el primer comando $ a = Invoke-RestMethod (...) es el que actualmente no funciona para mí. Funciona bien para un sitio HTTP, pero cuando introduce HTTPS que EM7 hace, devuelve el error descrito. Eso es para Invoke-RestMethod e Invoke-WebRequest. Estoy en el proceso de usar un cmdlet Invoke-Command y ejecutar curl.
floyd

1

Invoke-WebRequest "DomainName" -SkipCertificateCheck

Puede usar el parámetro -SkipCertificateCheck para lograr esto como un comando de una línea (ESTE PARÁMETRO SOLO SE APOYA EN LA PSEDICIÓN CORE)


0
  1. Ejecute este comando

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

en powershell con derechos de administrador , esto generará todos los certificados en el directorio personal

  1. Para deshacerse del error de privacidad, seleccione estos certificados, haga clic derecho → Copiar. Y pegue en Trusted Root Certification Authority / Certificates.
  2. El último paso es seleccionar enlaces correctos en IIS. Vaya al sitio web de IIS, seleccione Enlaces, seleccione la casilla de verificación SNI y configure los certificados individuales para cada sitio web.

Asegúrese de que el nombre de host del sitio web y el nombre DNS del certificado deben coincidir exactamente


0

Estas configuraciones de registro afectan a .NET Framework 4+ y, por lo tanto, a PowerShell. Configúrelos y reinicie las sesiones de PowerShell para usar el último TLS, no es necesario reiniciar.

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 

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


Para cualquiera que vea esta respuesta, nuestra experiencia es que este parche de registro requiere, de hecho, un reinicio para garantizar la funcionalidad adecuada. Al intentar garantizar una conexión TLS 1.2 entre un cuadro de Windows que ejecuta una aplicación .NET, se mostró SSL 3 a través de la traza de red para utilizarlo con este valor de registro, pero antes de reiniciar; TLS 1.2 se invocó solo después de un reinicio.
David W

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.