Подтвердить что ты не робот

Powershell Invoke-RestMethod через HTTPS

Я пытаюсь общаться с сервисом через powershell, но я терплю неудачу. Я подозреваю, что это сертификат, и я нашел ответ на этот вопрос и нашел два варианта, ни один из которых не работал у меня. Я также попытался объединить эти два безуспешно.

Вариант 1:

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

$urlJSON = "https://internal.ad.local/path/api_jsonrpc.php"

#Create authentication JSON object using ConvertTo-JSON
$objAuth = (New-Object PSObject | Add-Member -PassThru NoteProperty jsonrpc '2.0' |
Add-Member -PassThru NoteProperty method 'user.authenticate' |
Add-Member -PassThru NoteProperty params @{user="user";password="password"} |
Add-Member -PassThru NoteProperty id '2') | ConvertTo-Json


Invoke-RestMethod -Uri $urlJSON -body $objAuth -method "Post"

Вариант 2:

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

$urlJSON = "https://internal.ad.local/path/api_jsonrpc.php"

#Create authentication JSON object using ConvertTo-JSON
$objAuth = (New-Object PSObject | Add-Member -PassThru NoteProperty jsonrpc '2.0' |
Add-Member -PassThru NoteProperty method 'user.authenticate' |
Add-Member -PassThru NoteProperty params @{user="user";password="password"} |
Add-Member -PassThru NoteProperty id '2') | ConvertTo-Json


Invoke-RestMethod -Uri $urlJSON -body $objAuth -method "Post"

Здесь появляется сообщение об ошибке:

Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
At C:\Users\user\AppData\Local\Temp\46eaa6f7-62a0-4c10-88d1-79212d652bc9.ps1:24 char:1
+ Invoke-RestMethod -Uri $urlJSON -body $objAuth -method "Post"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Можно добавить:

  • серфинг непосредственно на службу работает с веб-браузером
  • Я также попытался открыть HTTP-сообщение, и это сработало
  • Сертификат, используемый службой, является самозаверяющим, но доверяется моей машиной через корневой сертификат (никаких предупреждений нет в IE или Chrome).
  • Я сделал сетевые захваты и убедился, что пакеты действительно достигают сервера.

Любые предложения оценены!

С уважением, Patrik

Обновлено сообщение о предложениях, сделанных г-ном Деревом ниже:

Name                       : lambda_method
DeclaringType              :
ReflectedType              :
Module                     : RefEmit_InMemoryManifestModule
MethodHandle               :
Attributes                 : PrivateScope, Public, Static
CallingConvention          : Standard
IsSecurityCritical         : False
IsSecuritySafeCritical     : False
IsSecurityTransparent      : True
ReturnType                 : System.Boolean
ReturnParameter            :
ReturnTypeCustomAttributes : System.Reflection.Emit.DynamicMethod+RTDynamicMethod+EmptyCAHolder
MemberType                 : Method
MethodImplementationFlags  : NoInlining
IsGenericMethodDefinition  : False
ContainsGenericParameters  : False
IsGenericMethod            : False
IsPublic                   : True
IsPrivate                  : False
IsFamily                   : False
IsAssembly                 : False
IsFamilyAndAssembly        : False
IsFamilyOrAssembly         : False
IsStatic                   : True
IsFinal                    : False
IsVirtual                  : False
IsHideBySig                : False
IsAbstract                 : False
IsSpecialName              : False
IsConstructor              : False
CustomAttributes           :
MetadataToken              :

Обновление 2 на основе комментария Mr Tree:

Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
At C:\Users\user\AppData\Local\Temp\ff47910e-fd8e-4be8-9241-99322144976a.ps1:13 char:1
+ Invoke-RestMethod -Uri $urlJSON -body $objAuth -method "Post"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
4b9b3361

Ответ 1

Я решил тайну, когда искал другую вещь. Веб-сервер, о котором идет речь, поддерживает только TLS1.1 и TLS1.2. Powershell, похоже, не поддерживает это. Если я включил TLS1.0, он работал.

Чтобы заставить TLS1.2 вы можете использовать эту строку:

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

Надеюсь, что поможет кому-то еще и спасибо за все полезные комментарии!

/Patrik

Ответ 2

Кажется, вы пытаетесь вызвать json API с помощью Invoke-RestMethod. В соответствии с документацией:

-ContentType

Задает тип содержимого веб-запроса.

Если этот параметр опущен, а метод запроса - POSTInvoke-RestMethod устанавливает тип содержимого для "применение/х-WWW-форм-urlencoded" . В противном случае тип содержимого не указан в вызове.

Чтобы использовать тело json, вам нужно использовать Invoke-RestMethod -ContentType 'application/json' <other args>

Ответ 3

Недавно я пережил много боли, чтобы пройти аналогичную ситуацию. Я создал доказательство концепции, используя пробную службу SaaS. Служба имела самоподписанный сертификат SSL, поэтому я хотел проигнорировать ошибки сертификата при попытке вызвать метод POST (аналогично параметру "-k" для curl). После большой борьбы я обнаружил, что для этого нужны оба: (a) вызов игнорировать ошибки проверки сертификата и (b) явный параметр для TLS 1.2 в качестве протокола безопасности. Я думаю, что последнее, потому что сервис, возможно, снизил попытки подключения с использованием любого из других протоколов. (Я потратил слишком много времени, пытаясь использовать разные варианты для каждого, как это предлагается для разных потоков SOF, но независимо...)

Здесь код, который работал...

Важное. Шлюз проверки сертификатов предназначен исключительно для прототипа /PoC. Мы не намерены делать это на производстве (и вы тоже не должны!).

$defaultSecurityProtocol = $null
try
{   
    #BUGBUG, TODO: Disabling cert validation for the duration of this call...('trial' version cert is self-signed.)
    #Remove this after the PoC.
    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } 
    #Cache the previous protocol setting and explicitly require TLS 1.2 
    $defaultSecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol
    [System.Net.ServicePointManager]::SecurityProtocol = `
                [System.Net.SecurityProtocolType]::Tls12

    if (-not [String]::IsNullOrWhiteSpace($authZHeaderValue))
    {
        $response = Invoke-WebRequest `
                    -Uri $webhookUrl `
                    -Method "Post" `
                    -Body $eventJson `
                    -Header @{ $authZHeaderName = $authZHeaderValue} 
    }
    else 
    {
        $response = Invoke-WebRequest `
                    -Uri $webhookUrl `
                    -Method "Post" `
                    -Body $eventJson
    }
}
catch 
{
    $msg = $_.Exception.Message
    $status = $_.Exception.Status
    $hr = "{0:x8}" -f ($_.Exception.HResult)
    $innerException = $_.Exception.InnerException
    #Just issue a warning about being unable to send the notification...
    Write-Warning("`n`t[$status] `n`t[0x$hr] `n`t[$msg] `n`t[$innerException]")
}
finally 
{
    # Set securityProtocol and CertValidation behavior back to the previous state.
    [System.Net.ServicePointManager]::SecurityProtocol = $defaultSecurityProtocol
        [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $null
}

Также хочу добавить, что предпочтительные протоколы безопасности продолжают меняться при обнаружении различных уязвимостей и исправлении. Более того, разные системы (стеки SSL/TLS в клиентских операционных системах и серверах/службах) часто имеют собственные возможности догонять самые последние/самые безопасные параметры. Таким образом, точно, какой флаг может работать, будет функционировать как клиентская, так и серверная системы, а также времени (при этом TLS1.2 может не оставаться предпочтительным несколько месяцев спустя). В идеале не обязательно указывать флаг вообще. Подробнее см. В разделе "Замечания" в этот документ MSDN.