it-swarm.com.ru

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)
  • Я сделал захват сети и убедился, что пакеты действительно достигают сервера.

Любые предложения приветствуются!

С уважением, Патрик

Обновленный пост относительно предложений, сделанных г-ном Триом ниже:

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 основано на комментарии г-на Древа:

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
13
PatrikJ

Я разгадал тайну, устраняя неисправности в другом. Рассматриваемый веб-сервер поддерживает только TLS1.1 и TLS1.2. Кажется, что Powershell НЕ поддерживает это. Если я включил TLS1.0, это сработало. 

Для форсирования TLS1.2 вы можете использовать эту строку:

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

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

/ Patrik

34
PatrikJ

Недавно я пережил много боли, чтобы преодолеть подобную ситуацию. Я создавал подтверждение концепции, используя пробную службу 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 для получения дополнительной информации.

0
mprabhu11

Похоже, вы пытаетесь вызвать json API с помощью Invoke-RestMethod. Согласно документации :

-Тип содержимого

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

Если этот параметр пропущен, а методом request является POST, Invoke-RestMethod устанавливает тип содержимого в "application/x-www-form-urlencoded". В противном случае тип содержимого - не указано в вызове.

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

0
Eris