Доверие к самоподписанному сертификату в вызове Invoke-WebRequest

Вопрос

Есть ли способ, которым я могу вызвать Invoke-WebRequest и, например, ожидать, что данный открытый ключ сертификата подтвердит, что я доверяю соединению?

Если нет, есть ли другой способ вызвать веб-запрос и доверять только веб-странице, не доверяя эмитенту или игнорируя проверку сертификата?

Проблема

Я хочу загрузить веб-страницу с помощью Invoke-WebRequest. Я пытаюсь подключиться к веб-странице через https, и сервер предлагает самоподписанный сертификат.

Поскольку у меня нет сертификата эмитента в моем хранилище сертификатов, Invoke-WebRequest выдаст ошибку:

Invoke-WebRequest : The remote certificate is invalid according to the validation procedure.

Известные обходные пути

  1. Использование переключателя -SkipCertificateCheck, добавленного в Powershell v6.0.0 ссылка
  2. Добавление новой политики сертификата для доверия всем сертификатам ссылка
  3. Доверие к эмитенту-сертификату

Что я пробовал, но не получилось

  1. Добавление сертификата веб-страницы в хранилище сертификатов без доверия к сертификату издателя
  2. Добавление сертификата веб-страницы в хранилище сертификатов и использование -Certificate-параметра Invoke-WebRequest для указания этого сертификата

PS: поскольку эта проблема возникает как в Powershell <5, так и в Powershell Core, я помечаю оба.

3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
3
0
7 492
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Короткий ответ: нет, вы не можете обойти это, а когда дело доходит до сертификатов, даже не пытайтесь. Клиент сначала просматривает сертификат и всю цепочку сертификатов, чтобы убедиться, что ему доверяют. Если какая-либо часть этой цепочки (например, эмитент) не является доверенной, то она не является доверенной. Если бы этого фундаментального факта не было, то отзывать сертификаты было бы невозможно.

Для самоподписанных сертификатов, поскольку они не являются доверенными, вы правы, на самом деле у клиента есть только 2 варианта:

  1. Игнорируйте происхождение сертификата и подключайтесь вслепую с помощью переключателя -SkipCertificateCheck.
  2. Примите, что эмитенту и всей цепочке можно доверять, и импортируйте сертификат.

Вы не можете обойти этот фундаментальный факт. Мне нравится использовать пример: самоподписанные сертификаты подобны доставке клиенту объекта в форме бомбы с наклейкой на нем, говорящей: «Не бомба - поверьте мне, я @Paxz». Цепочки сертификатов похожи на то, что когда вы держите объект в форме бомбы, вы смотрите на водителя доставки, и они выглядят очень подозрительно, и в то же время совсем не похожи на @Paxz. Затем у вас есть выбор: либо игнорировать наклейку, либо согласиться с тем, что я могу доверять @Paxz и сомнительному водителю доставки. Вы не можете просто засунуть посылку через парадную дверь без явного согласия. Когда вы доверяете всей цепочке, на наклейке будет написано «Не бомба - поверьте мне, я был проверен экспертами по бомбам», поскольку вы доверяете экспертам по бомбам, клиент без вопросов примет посылку.

Хм.. Я надеялся получить другой ответ... :'D Но боялся, что так получится. Я подожду еще неделю в надежде, что появится что-то еще, если нет, я отмечу этот ответ как правильный (до тех пор примите мой голос). А так же спасибо за анекдот!

Paxz 22.05.2019 20:15

Мне нужно надежное соединение с моим сервером Icinga2, и я нашел способ сравнить один сертификат.

Это основной код, который хранит сертификат [X509Certificate2] для сравнения и устанавливает функцию обратного вызова для проверки сертификата.

function set-SSLCertificate {
    param(
        $Cert
    )

    if (-not("validateCert" -as [type])) {
        add-type -TypeDefinition @"
            using System.Net.Security;
            using System.Security.Cryptography.X509Certificates;

            public static class ValidateCert {
                static X509Certificate2 MyCert;

                public static bool Validate(object sender,
                    X509Certificate cert,
                    X509Chain chain,
                    SslPolicyErrors sslPolicyErrors) {
                        if (MyCert.Equals(cert)) {
                            return true;
                        } else {
                            return false;
                        }
                }

                public static RemoteCertificateValidationCallback GetDelegate(X509Certificate2 Cert) {
                    MyCert = Cert;
                    return new RemoteCertificateValidationCallback(ValidateCert.Validate);
                }
            }
"@
    }
    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = [validateCert]::GetDelegate($Cert)
}

Вам нужен сертификат как [X509Certificate2].

Я использую эту функцию для преобразования сертификата в формате Base64, который легко хранить внутри переменных.

function get-x509 {
    param(
        [string]
            $Cert64
    )

    $CertBin=[System.Convert]::FromBase64String(($Cert64.Trim(" ") -replace "-.*-",""))

    [System.Security.Cryptography.X509Certificates.X509Certificate2]$CertBin
}

Все дело в подключении SSL сервера:

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

$SecPass = ConvertTo-SecureString $Pass -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential($User, $SecPass)

$Cert = get-x509 $Cert64
set-SSLCertificate $Cert

Invoke-RestMethod -Uri $URL -Credential $Cred

Чтобы получить старое поведение:

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = $null

Другие вопросы по теме