第15课:如何用

第15课:如何用 PowerShell 访问 HTTPS 的应用

在上一篇内容中和大家分享了如何用 Java 代码访问 HTTPS 的应用,其实不仅仅是编程语言里面,比如 Java 语言,有访问 HTTPS 的关键要点,脚本访问 HTTPS 的相关应用的时候也有一些坑和技巧。 因为编程语言已经选择了 Java 为代码,所以本节将分享一类脚本语言访问 HTTPS 时,应该如何做?有什么坑和技术要点。因为笔者最近在做一个基于 PowerShell DSC 的自动化运维项目,对 PowerShell 积累的不少的经验,所以本节内容就选择了 PowerShell 这个 Windows 操作系统的上脚本语言为例和大家分享一下如何用 PowerShell 来访问基于 HTTPS 的应用。

如果大家对 PowerShell DSC 有兴趣的话,可以参考 CSDN 博客,里面有很详细的说明;如果大家对 Windows 上的成千上万的机器如何自动化运维,可以参考我另外的一篇 GitChat 文章《大规模私有云产品自动升级的框架选型和实战》

PowerShell 环境准备和简介

PowerShell 本身没有独立的安装包,Powershell 是 Window Management Framework(WMF,Window 管理框架)的一部分。当前 Window Management Framework 的最新版本是 5.1,当前主流的 Windows 操作系统上面都会默认安装 PowerShell,默认情况下其提供了两种让我们进行交互的方式:一种是打开 PowerShell 的命令行窗体(分 64 位[Windows Powershell]和 32 位[Windows Powershell(x86)]);另一种是打开 PowerShell 的编辑软件,PowerShell ISE。

enter image description here

可以通过下面的命令来查看 Windows 机器上 PowerShell 的最新版本。

$PSVersionTable

enter image description here

笔者当前安装的就是 PowerShell 5.1 版本,如果要升级成最新的 PowerShell 5.1 版本,则需要先安装 .NET 4.5.2 和 Windows Management Framework 5.1,Windows Management Framework 升级为了 5.1,PowerShell 就自动升级成了 5.1 版本。Windows Management Framework 5.1 的下载地址详见这里

其支持下面的服务器的升级安装,选择一个适合你的 Windows 操作系统平台。具体安装步骤,就不再赘述,如果有任何的安装问题,欢迎大家在我的读者圈留言。

enter image description here

需要注意的是,Windows Management Framework 5.1 依赖于 .NET 4.5.2 或者以上版本,所以安装 Windows Management Framework 5.1 之前,请先确保你已经安装了 .NET 4.5.2 或者以上版本。

使用 PowerShell 调用 HTTPS 站点出现的主要问题

PowerShell 有一个命令,Invoke-WebRequest 可以调用和访问 HTTPS 的应用,通过使用 Invoke-WebRequest 可以获得一个网页或者 Web 服务。其一个简单的应用就是,比如调用 Invoke-WebRequest 方法,去爬京东网站的商品信息,那么首先要进入京东网站的首页,直接使用下面的命令。

Invoke-WebRequest 'https://www.jd.com/'

enter image description here

可以发现,其正确地把京东网站首页的 HTML 的源代码成功返回。

但是,如果我调用的是,在《第10课:IIS 如何配置 HTTPS》 一课中的网站的时候,其命令类似如下:

Invoke-WebRequest 'https://iis-web-01/'

因为“https://iis-web-01/”站点是基于私有 CA 根证书(51TalkDocter Root CA)签发的,如下图,而我所在的测试机恰好没有把其导入 Windows 操作系统的可信任证书里面。

那么调用的结果会成功吗?

enter image description here

从上图可以看出,其调用“https://iis-web-01/”站点失败,那么如何解决这个问题呢?

使用 PowerShell 调用 HTTPS 站点的常见解决方案

解决上述 PowerShell 调用 HTTPS 站点出现的 SSL 安全连接不能成功建立的方法有很多种,下面逐一列举出几种解决方案。

1. 把私有 CA 的根证书导入到操作系统的受信任的根证书颁发机构

关于如何把私有 CA 的根证书导出,并导入到操作系统的受信任的根证书颁发机构里面,可以参考《第12课:Tomcat 配置 HTTPS 进阶篇》 的配置 Tomcat 的 HTTPS的章节,里面有下面一张图的部分提到了导出和导入的方法,这里就不再赘述。

导入成功后,其基于 HTTPS 的调用就成功了。

注意,只需要导入其私有 CA 的根证书到操作系统的受信任的根(Root)证书颁发机构里面,“https://iis-web-01/”站点本身的服务器的 SSL 证书不需要导入到受信任的根证书颁发机构里。但是如果 HTTPS 的服务器是自签名的话,这种情况下就需要把这个 HTTPS 站点的自签名证书导入到操作系统的受信任的根证书颁发机构里。

2. 让客户端忽略对服务器端的 SSL 证书的校验

如果在测试环境,而不是在生产环境,其实也可以使用下面的方式来忽略对 HTTPS 服务器端证书的校验。通过在 PowerShell 的控制台执行下面的命令:

if (-not ([System.Management.Automation.PSTypeName]'ServerCertificateValidationCallback').Type)
{
$certCallback = @"
    using System;
    using System.Net;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    public class ServerCertificateValidationCallback
    {
        public static void Ignore()
        {
            if(ServicePointManager.ServerCertificateValidationCallback ==null)
            {
                ServicePointManager.ServerCertificateValidationCallback += 
                    delegate
                    (
                        Object obj, 
                        X509Certificate certificate, 
                        X509Chain chain, 
                        SslPolicyErrors errors
                    )
                    {
                        return true;
                    };
            }
        }
    }
"@
    Add-Type $certCallback
 }
[ServerCertificateValidationCallback]::Ignore()

执行完成后,再执行下面的命令,发现其执行成功。

 Invoke-WebRequest 'https://iis-web-01/'

这种解决方案不建议在生产环境中使用,特别是在互联网的环境下,因为其让客户端忽略了对 HTTPS 服务器端的证书校验,可能造成安全隐患。上面的解决方案其实就是执行了 C# 的代码方法[ServerCertificateValidationCallback]::Ignore(),让客户端忽略检查服务器证书,有点类似于使用 IE 浏览器访问一个不受信任的 HTTPS 站点一样,其会提示你是否信任并继续。在当前的 PowerShell 5.1 的版本,每次使用的时候都需要在 PowerShell 的环境下执行上面的一段 C# 代码,也许微软也意识到了这样非常的不方便,所以在新的 PowerShell Core 6.0 的跨平台版本里面,Invoke-WebRequest cmdlet 里面专门提供了一个参数 -SkipCertificateCheck 来自动忽略其对服务器证书的校验。

小小透露一下,PowerShell 6.0 不仅仅能在 Windows 的操作系统上安装,也能下面的非 Linux 系统安装,而且还是开源的。是不是彻底刷新了我们对微软的认识?还等什么,好奇的话,可以下载一个试试。

enter image description here

3. 通过脚本自动导入私有 CA 的根证书

上面的第1个解决方案当中,我们需要手动导入 https://iis-web-01/ 目标站点的私有根 CA 证书到 Windows 操作系统的受信任的根(Root)证书颁发机构里面去,但是如果在一些自动运维项目中,运行 Invoke-WebRequest 方法调用 HTTPS 站点的时候,这个命令可能需要运行在成千上万的客户端,如果每个客户端都手动导入证书,可想而知工作量是有多么的大。如果能通过 PowerShell 脚本自动把证书导入到 Windows 操作系统的受信任的根(Root)证书颁发机构里面,那就事半功倍了!

Certutil 工具隆重出场,在使用前先对 Certutil 进行简单介绍。

certutil.exe 是 Windows 操作系统默认自带的一个功能非常强大的工具,可以使用 Certutil.exe 来操作和显示证书颁发机构(CA)信息,配置证书服务,备份和还原 CA 组件,并验证证书,密钥对和证书链。

可以通过下面的命令来查看其提供的功能。

certutil -v -?

其中有一个子命令,CertUtil -addstore 就是我们这次需要使用的,其作用就是把特定的 SSL 证书添加到操作系统的证书管理系统里去。其命令格式说明如下:

CertUtil [Options] -addstore CertificateStoreName InFile

其中:

(1)CertificateStoreName 为证书存储仓库类型的名字,在 Window 操作系统里面,其主要包括下面这些仓库类型。

  • TrustedPublisher
  • Root
  • UserDS
  • CA
  • ACRS
  • REQUEST
  • AuthRoot
  • TrustedPeople
  • addressbook
  • My
  • SmartCardRoot
  • Trust
  • Disallowed

为什么是上面的这些证书仓库类型呢?请参考《第03课:Windows 操作系统下如何管理 SSL 证书》,里面提到了提到了 ls Cert:\CurrentUser\ 这个命令。

(2)InFile 就是需要导入的 SSL 证书的全路径

假设 https://iis-web-01/ 目标站点的私有根 CA 证书已经导出到 C:\ssldemo\powershell\51TalkDocter_Root_CA.cer,那么可以使用下面的命令把当前证书导入到操作系统的受信任的根(Root)证书颁发机构里面。

PS C:\ssldemo\powershell> certutil -addstore Root  'C:\ssldemo\powershell\51TalkDocter_Root_CA.cer'

Root
Signature matches Public Key
Related Certificates:

Exact match:
Element 7:
Serial Number: 01
Issuer: E=chancein007@163.com, CN=51TalkDocter Root CA, OU=IT, O=51talkdocter, L=xian, S=shannxi, C=cn
 NotBefore: 2018/3/6 15:04
 NotAfter: 2019/3/6 15:04
Subject: E=chancein007@163.com, CN=51TalkDocter Root CA, OU=IT, O=51talkdocter, L=xian, S=shannxi, C=cn
Signature matches Public Key
Root Certificate: Subject matches Issuer
Template: 
Cert Hash(sha1): 36 a8 8c c5 c9 4b d3 26 a3 96 8a 59 d6 07 2e a6 4f 13 36 9a

Certificate "E=chancein007@163.com, CN=51TalkDocter Root CA, OU=IT, O=51talkdocter, L=xian, S=shannxi, C=cn" already in store.
CertUtil: -addstore command completed successfully.

这个时候,再次调用 Invoke-WebRequest 'https://iis-web-01/' 去访问目标的 HTTPS 站点的时候,成功返回!

总结

考虑 PowerShell 6 已经开源,其不仅仅支持 Windows 操作系统的安装,而且还支持 Linux、Unix 和 Mac 系统的安装,未来 PowerShell 应该会被应用的越来越多,所以笔者以 PowerShell 5.1 的版本为例子,和大家分享了如果用 PowerShell 的 Invoke-WebRequest 命令来访问基于 HTTPS 的网站,目的是引出调用 HTTPS 的时候,将会出现的调用异常,如果对于 Restful 风格的 API, PowerShell 也提供了另外一个命令 Invoke-RestMethod,大家有兴趣可以试试。

一般情况下,PowerShell 调用由世界上著名的 CA 证书中心颁发的商业网站是不会抛出任何异常的。但是,如果调用有企业自己内部私有 CA 签署的 HTTPS Web 服务器站点的时候,有可能会调用失败。 笔者针对这种情况,给出了三种通用的解决方案,当然解决办法远远不止这些,希望能够起到抛砖引玉的作用。如果大家有任何的好的建议或者任何相关问题,请在我的读者圈里留言,最后祝大家学习愉快!

上一篇
下一篇
目录