【问题标题】:Powershell Invoke-RestMethod over HTTPSPowershell Invoke-RestMethod over HTTPS
【发布时间】:2015-09-02 14:13:29
【问题描述】:

我正在尝试通过 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

【问题讨论】:

  • 在第二个示例中尝试{$true} -as [Net.Security.RemoteCertificateValidationCallback]...您是否在 LocalMachine 或 CurrentUser 存储中安装了 CA?
  • 感谢您的帮助。 CA 安装在我的 CurrentUser 和 Computer 帐户下的 Trusted Root Certification 中。将添加您在我上面的帖子中发布的命令的结果。
  • (不知道该在那里寻找什么)
  • 如果您从选项 2 [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} 中删除以下内容,您会得到什么。然后重启Powershell并重新运行脚本?
  • 感谢您的建议。我得到和以前一样的错误。该帖子已更新详细信息。

标签: powershell ssl https self-signed invoke-command


【解决方案1】:

我在解决另一件事的同时解决了这个谜团。有问题的 Web 服务器仅支持 TLS1.1 和 TLS1.2。 Powershell 似乎不支持这一点。如果我启用了 TLS1.0,它就可以工作。

要强制 TLS1.2,您可以使用此行:

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

希望对其他人有所帮助,并感谢所有有用的 cmets!

/帕特里克

【讨论】:

  • 帮了我很多忙。感谢发帖!
  • 来自 8.2.1 版的新 DellEMC Isilon 模拟器似乎具有用于内置 apache Web 服务器的 TLS1.2。 PatrickJ 提供的这个更正使它们在新平台上运行。谢谢!
【解决方案2】:

您似乎正在尝试使用 Invoke-RestMethod 调用 json API。根据documentation

-内容类型

指定网络请求的内容类型。

如果省略此参数且请求方法为POST, Invoke-RestMethod 将内容类型设置为 “应用程序/x-www-form-urlencoded”。否则,内容类型为 调用中未指定。

要使用 json 正文,您需要使用 Invoke-RestMethod -ContentType 'application/json' <other args>

【讨论】:

    【解决方案3】:

    为了摆脱类似的情况,我最近经历了很多痛苦。我正在使用试用 SaaS 服务创建概念验证。该服务有一个自签名 SSL 证书,因此我想在尝试对其调用 POST 方法时忽略证书错误(类似于 curl 的“-k”参数)。经过一番努力,我发现它需要 both - (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 可能不再是首选)。理想情况下,根本不需要指定标志。更多内容请参见this MSDN document中的“备注”部分。

    【讨论】:

      【解决方案4】:

      这是一个对我有用的完整 Powershell 脚本:

      try {
          # Configure API request payload
          $url = "https://my.server.com/api/countries"
          $method = "POST"
          $headers = @{
                        "Content-Type" = "application/json"
                     }
          $body = '{
                    "name": "India"
                  }'
          # Reading request body from json file
          # $body = Get-Content request.json | Out-String
          $certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 "C:\ClientCert.pfx", "Password1"
       
          # Call the API
          Invoke-RestMethod -Uri $url -Method $method -Headers $headers -Body $body -Certificate $certificate
          
          Write-Host "`n#################### SUCCESS ####################`n"
      } catch {
          Write-Host "`n#################### ERROR ####################`n"
      
          # Getting response code
          $responseCode = $_.Exception.Message
          
          # Getting response body
          if ($_.Exception.Response -ne $null) {
              $responseStream = $_.Exception.Response.GetResponseStream()
              $streamReader = New-Object System.IO.StreamReader($responseStream)
              $streamReader.BaseStream.Position = 0
              $streamReader.DiscardBufferedData()
              $responseBody = $streamReader.ReadToEnd()
          }
          
          Write-Host "Response Code - " $responseCode
          Write-Host "Response Body - " $responseBody
          
          Write-Host "`n###############################################`n"
      }
      

      【讨论】:

        猜你喜欢
        • 2015-02-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-20
        • 1970-01-01
        • 2017-04-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多