You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Function用客户端证书发HTTPS请求遇UntrustedRoot错误

问题分析与解决方案

你的核心问题是:Azure Function的Windows宿主环境不信任目标服务器证书的根CA,你尝试的几种方法存在关键逻辑错误,导致无法绕过证书链验证失败的问题。

错误点拆解

  1. 自定义验证回调逻辑失效:你在回调中直接使用了传入的$certificateChain参数,没有将自己上传的CA证书注入到验证链中,相当于自定义CA根本没参与验证。
  2. 验证回调范围不覆盖所有请求方式:ServicePointManager.ServerCertificateValidationCallback仅对旧的HttpWebRequest生效,PowerShell 7+的Invoke-RestMethod/HttpClient默认使用SocketsHttpHandler,不受该回调影响。
  3. 混淆客户端证书与信任CA的用途:你将客户端证书上传到Function App的操作,是用于服务端验证你的请求身份,而非让Function信任目标服务器的CA证书。

针对性解决方案

方案1:修复自定义证书验证回调(兼容所有请求方式)

修改验证逻辑,在回调内部重新构建包含自定义CA的证书链,确保自定义CA参与验证:

# 提前加载CA证书(建议放在函数初始化块,避免重复加载)
$caCertPaths = @(
    "C:\home\ca-certificates\issuing_3.cer",
    "C:\home\ca-certificates\intermediate_2.cer",       
    "C:\home\ca-certificates\root_1.cer" 
)
$trustedCAs = @()
foreach ($path in $caCertPaths) {
    $certBytes = [System.IO.File]::ReadAllBytes($path)
    $trustedCAs += [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($certBytes)
}

# 注册全局验证回调(同时兼容HttpWebRequest和HttpClient)
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {
    param(
        $sender,
        [System.Security.Cryptography.X509Certificates.X509Certificate]$cert,
        [System.Security.Cryptography.X509Certificates.X509Chain]$chain,
        [System.Net.Security.SslPolicyErrors]$sslErrors
    )

    # 无错误直接通过
    if ($sslErrors -eq [System.Net.Security.SslPolicyErrors]::None) {
        return $true
    }

    # 构建自定义验证链,注入我们的CA证书
    $customChain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
    $customChain.ChainPolicy.ExtraStore.AddRange($trustedCAs)
    # 禁用默认根CA检查,仅信任我们添加的CA
    $customChain.ChainPolicy.VerificationFlags = [System.Security.Cryptography.X509Certificates.X509VerificationFlags]::AllowUnknownCertificateAuthority
    # 关闭吊销检查(内部CA通常无需配置)
    $customChain.ChainPolicy.RevocationMode = [System.Security.Cryptography.X509Certificates.X509RevocationMode]::NoCheck

    # 执行验证
    $isValid = $customChain.Build([System.Security.Cryptography.X509Certificates.X509Certificate2]$cert)
    
    # 调试输出错误(可选)
    if (-not $isValid) {
        Write-Host "证书链验证失败:"
        foreach ($status in $customChain.ChainStatus) {
            Write-Host "- $($status.StatusInformation)"
        }
    }
    return $isValid
}

方案2:针对PowerShell 7+的Invoke-RestMethod使用专用Handler

PS7+的Invoke-RestMethod默认使用SocketsHttpHandler,可以直接给它指定验证逻辑,避免全局回调的潜在冲突:

# 加载自定义CA证书
$caCertPaths = @(
    "C:\home\ca-certificates\issuing_3.cer",
    "C:\home\ca-certificates\intermediate_2.cer",       
    "C:\home\ca-certificates\root_1.cer" 
)
$trustedCAs = @()
foreach ($path in $caCertPaths) {
    $certBytes = [System.IO.File]::ReadAllBytes($path)
    $trustedCAs += [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($certBytes)
}

# 创建自定义SocketsHttpHandler
$handler = [System.Net.Http.SocketsHttpHandler]::new()
$handler.ServerCertificateCustomValidationCallback = {
    param(
        $sender,
        [System.Security.Cryptography.X509Certificates.X509Certificate]$cert,
        [System.Security.Cryptography.X509Certificates.X509Chain]$chain,
        [System.Net.Security.SslPolicyErrors]$sslErrors
    )

    # 构建自定义验证链
    $customChain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
    $customChain.ChainPolicy.ExtraStore.AddRange($trustedCAs)
    $customChain.ChainPolicy.VerificationFlags = [System.Security.Cryptography.X509Certificates.X509VerificationFlags]::AllowUnknownCertificateAuthority
    $customChain.ChainPolicy.RevocationMode = [System.Security.Cryptography.X509Certificates.X509RevocationMode]::NoCheck

    return $customChain.Build([System.Security.Cryptography.X509Certificates.X509Certificate2]$cert)
}

# 添加客户端证书(如果需要)
$pfxCert = Get-AzKeyVaultSecret -VaultName $vaultName -Name $pfxCertName -AsPlainText
$pfxBytes = [System.Convert]::FromBase64String($pfxCert)
$clientCert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
    $pfxBytes, 
    "", 
    [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet
)
$handler.ClientCertificates.Add($clientCert)

# 发起请求
$client = [System.Net.Http.HttpClient]::new($handler)
$response = $client.GetAsync($URI).GetAwaiter().GetResult()
$responseContent = $response.Content.ReadAsStringAsync().GetAwaiter().GetResult()

方案3:将CA证书导入Function宿主信任存储(永久解决)

如果你的CA是企业内部合法根CA,可以通过Kudu控制台将证书导入宿主机器的信任存储,一劳永逸:

  1. 打开Function App的Kudu调试控制台:https://<你的函数应用名>.scm.azurewebsites.net/DebugConsole
  2. 执行以下命令导入证书:
# 导入根CA到信任根存储
certutil -addstore -f "Root" "C:\home\ca-certificates\root_1.cer"
# 导入中间CA到中级CA存储
certutil -addstore -f "CA" "C:\home\ca-certificates\intermediate_2.cer"
certutil -addstore -f "CA" "C:\home\ca-certificates\issuing_3.cer"
  1. 重启Function App,之后所有HTTPS请求会自动信任该CA签发的证书

关键注意事项

  • 生产环境禁止使用{ $true }跳过证书验证,会引入严重安全风险
  • 加载客户端证书时必须指定X509KeyStorageFlags::MachineKeySet,避免Azure Function临时存储的权限问题
  • PowerShell 7.2的-SkipCertificateCheck参数受Function沙箱限制,不建议依赖

内容的提问来源于stack exchange,提问作者ABF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 14:14:56