企业证书固定概述

企业证书固定是一项 Windows 功能,用于记住 (将) 、根证书颁发机构或最终实体证书固定到域名。
此功能通过防止内部域名链接到不需要或欺诈性颁发的证书,有助于减少中间人攻击。

注意

外部域名的证书是由公共证书颁发机构颁发的,不适合企业证书固定。

(CertVerifyCertificateChainPolicyWinVerifyTrust) 的 Windows 证书 API 将更新为检查,前提是对服务器进行身份验证的站点链与一组受限的证书匹配。
这些限制封装在配置并部署到 Windows 设备的 固定规则证书信任列表中, (CTL)
触发名称不匹配的任何站点证书都会导致 Windows 将事件写入 CAPI2 事件日志,并阻止用户浏览网站。

注意

企业证书固定功能触发不会导致 Microsoft Edge 以外的客户端阻止连接。

部署

若要部署企业证书固定,你需要:

  • 创建格式完善的证书固定规则 XML 文件
  • 从 XML 文件创建 pin 规则证书信任列表文件
  • 将 pin 规则证书信任列表文件应用到引用管理计算机
  • 通过组策略在引用计算机上部署注册表配置

创建固定规则 XML 文件

基于 XML 的 pin 规则文件包含一系列 PinRule 元素。 每个 PinRule 元素包含一系列一个或多个站点元素以及一系列零个或多个证书元素。

<PinRules ListIdentifier="PinRulesExample" Duration="P28D">

  <PinRule Name="AllCertificateAttributes" Error="None" Log="true">
    <Certificate File="Single.cer"/>
    <Certificate File="Multiple.p7b"/>
    <Certificate File="Multiple.sst"/>
    <Certificate Directory="Multiple"/>
    <Certificate Base64="MIIBy … QFzuM"/>
    <Certificate File="WillExpire.cer" EndDate="2015-05-12T00:00:00Z"/>
    <Site Domain="xyz.com"/>
  </PinRule>

  <PinRule Name="MultipleSites" Log="false">
    <Certificate File="Root.cer"/>
    <Site Domain="xyz.com"/>
    <Site Domain=".xyz.com"/>
    <Site Domain="*.abc.xyz.com" AllSubdomains="true"/>
    <Site Domain="WillNormalize.com"/>
  </PinRule>

</PinRules>

PinRules 元素

PinRules 元素具有以下属性: 有关设置固定规则格式的帮助,请参阅 在 XML 中表示日期用 XML 表示持续时间

属性 说明 必需
DurationNextUpdate 指定固定规则的过期时间。 必须指定任何一种属性。 如果指定了两种属性,则NextUpdate 优先级更高。
持续时间(表示为 XML TimeSpan 数据类型)不允许年和月。 以 UTC 格式将 NextUpdate 属性表示为 XML DateTime 数据类型。
是否为必需? 是。 至少需要一种属性。
LogDurationLogEndDate 配置审核以仅超出强制执行 Pin 规则的到期日期。
LogEndDate 表示为采用 UTC 的 XML DateTime 数据类型,如果指定了两种属性则其优先级更高。
可以将 LogDuration 表示为 XML TimeSpan 数据类型,这不允许使用年和月。
如果未指定任何属性,则审核过期将使用 DurationNextUpdate 属性。
否。
ListIdentifier 为固定规则列表提供易记名称。 Windows 不使用此属性执行证书固定;但是,在将固定规则转换为证书信任列表 (CTL) 时,会包含该规则。 否。

PinRule 元素

PinRule 元素具有以下属性。

属性 说明 必需
Name 唯一标识 PinRule。 Windows 使用 特性来标识分析错误或详细输出的元素。 (CTL) 生成的证书信任列表中不包含 属性。 是。
Error 描述 Windows 遇到 PIN 不匹配时执行的操作。 你可以从以下字符串值中进行选择:
- Revoked - Windows 报告吊销的证书以保护站点。 这通常会阻止用户访问该站点。
- InvalidName - Windows 报告保护站点的证书,就像证书上的名称与站点名称不匹配一样。 这通常会在用户访问该站点之前提示用户。
- None - 默认值。 不会返回错误。 可以使用 设置来审核固定规则,而不会引入任何用户摩擦。
否。
Log 布尔值表示等于 truefalse 的字符串。 默认情况下,日志记录会被启用 (true)。 否。

证书元素

证书元素具有以下属性。

属性 说明 必需
File 指向包含一个或多个证书的文件的路径。 这种情况下证书可以编码为:
- 单个证书
- p7b
- sst
这些文件也可以采用 Base64 格式。 同一 PinRule 元素中包含的所有站点元素都可以匹配这些证书中的任意一种。
是 (文件、目录或 Base64 必须) 。
Directory 指向包含一个或多个上述证书文件的目录的路径。 跳过不包含任何证书的任何文件。 是 (文件、目录或 Base64 必须) 。
Base64 Base64 编码证书。 这种情况下证书可以编码为:
- 单个证书
- p7b
- sst
这可以让证书包含在没有文件目录依赖关系的 XML 文件中。
注意:
可以使用 certutil -encode 将 .cer 文件转换为 base64。 然后可以使用记事本复制 base64 编码证书并将其粘贴到固定规则。
是 (文件、目录或 Base64 必须) 。
EndDate 能够用于配置到期日期以规定固定规则中的证书不再有效的时间。
如果正在切换到新的根或 CA,则可以设置 EndDate 以允许匹配此元素的证书。
如果当前时间超过 EndDate,则创建证书信任列表 (CTL) 分析器会输出警告消息,并从生成的 CTL 中的固定规则中排除证书 () 。
有关设置固定规则格式的帮助,请参阅 在 XML 中表示日期
否。

站点元素

站点元素具有以下属性。

属性 说明 必需
Domain 包含将与此固定规则相匹配的 DNS 名称。 创建证书信任列表时,分析程序将规范化输入名称字符串值,如下所示:
- 如果 DNS 名称具有前导“*”,则删除它。
- 非 ASCII DNS 名称转换为 ASCII Puny Code。
- 大写的 ASCII 字符将转换为小写。
如果规范化名称具有前导“.”,则启用通配符左侧标签匹配。 例如,“.xyz.com”将与“abc.xyz.com”匹配。
是。
AllSubdomains 默认情况下,通配符左侧标签匹配仅限于单个左侧标签。 此属性可以设置为“true”以针对所有左侧标签启用通配符匹配。
例如,设置此属性也会将“123.abc.xyz.com”与“.xyz.com”域值相匹配。
否。

创建固定规则证书信任列表

Certutil.exe 命令包含 generatePinRulesCTL 参数。 参数分析 XML 文件,并生成编码证书信任列表 (CTL) ,你将其添加到引用 Windows 设备,然后进行部署。 语法为:

CertUtil [Options] -generatePinRulesCTL XMLFile CTLFile [SSTFile]
  Generate Pin Rules CTL
    XMLFile -- input XML file to be parsed.
    CTLFile -- output CTL file to be generated.
    SSTFile -- optional .sst file to be created.
         The .sst file contains all of the certificates
         used for pinning.

Options:
  -f                -- Force overwrite
  -v                -- Verbose operation
  • 多个 PinRule 元素中可能会出现相同的证书 ()
  • 同一域可以出现在多个 PinRule 元素中
  • Certutil 将这些合并到生成的引脚规则证书信任列表中
  • Certutil.exe 不严格强制实施 XML 架构定义

Certutil 执行以下操作,使其他工具能够添加/使用自己的特定元素和属性:

  • 跳过 PinRules 元素之前和之后的元素
  • 跳过 PinRules 元素中与证书站点不匹配的任何元素
  • 跳过与每个元素类型的上述名称不匹配的任何属性

使用带 generatePinRulesCTL 参数的 certutil 命令以及包含证书固定规则的 XML 文件。 最后提供输出文件的名称,该输出文件将包括证书信任列表格式的证书固定规则。

certutil -generatePinRulesCTL certPinRules.xml pinrules.stl

将证书固定规则应用于引用计算机

现在证书固定规则已采用证书信任列表格式,你需要将设置应用到引用计算机,这是将设置部署到企业的先决条件。 为了简化部署配置,最好将证书固定规则应用于具有 组策略 管理控制台 (GPMC) 包含在远程服务器管理工具 (RSAT) 中的计算机。

使用 certutil.exe 以将证书固定规则应用到使用 setreg 参数的引用计算机。
setreg 参数具有一个辅助参数以确定 certutil 写入证书固定规则的位置。
辅助参数为 chain\PinRules
提供的最后一个参数是包含证书信任列表格式的证书固定规则的文件的名称, (.stl) 。
将文件的名称作为最后一个参数传递。 必须使用 符号作为文件名 @ 的前缀,如以下示例所示:

Certutil -setreg chain\PinRules @pinrules.stl

注意

必须从提升的命令提示符执行命令。

Certutil 会将二进制信息写入以下注册位置:

名称
HKLM\SOFTWARE\Microsoft\Cryptography\OID\EncodingType0\CertDllCreateCertificateChainEngine\Config
名称 PinRules
证书 pin 规则证书信任列表文件的二进制内容
数据类型 REG_BINARY

注册表二进制信息。

使用组策略部署企业 PIN 规则设置

在 XML 文件中,你已创建证书固定信任列表文件。 然后,你已将文件的内容应用到可从中运行 组策略 管理控制台的引用设备。

下一步包括配置包含已应用证书固定规则设置的组策略对象,并将其部署到环境中。

使用域管理员等效凭据登录到引用计算机。

  1. 启动组策略管理控制台 (gpmc.msc)
  2. 在导航窗格中,展开林节点,然后展开域节点
  3. 展开包含 Active Directory 域名的节点
  4. 选择组策略对象节点。 右键单击“组策略对象”节点,然后选择“新建
  5. 在“新建 GPO”对话框中,在“名称”文本框中键入“企业证书固定规则”,然后选择“确定”
  6. 在内容窗格中,右键单击“企业证书固定规则”组策略对象,然后选择“编辑
  7. 组策略管理编辑器中,在导航窗格中展开计算机配置下的首选项节点。 展开 “Windows 设置”
  8. 右键单击“注册表”节点,然后选择“新建
  9. 新注册表属性对话框中,从操作列表中选择更新。 从 Hive 列表中选择HKEY_LOCAL_MACHINE
  10. 对于 “密钥路径”,请选择“ ...” 以启动 注册表项浏览器。 导航到以下注册表项并选择 PinRules 注册表值名称:

HKLM\SOFTWARE\Microsoft\Cryptography\OID\EncodingType0\CertDllCreateCertificateChainEngine\Config

选择 “选择” 以关闭 注册表项浏览器

  1. 注册表项路径应包含选定的注册表项。 值名称配置应包含注册表值名称 PinRules值类型读取REG_BINARY数据 应包含 0-9 之间的长系列数字和从 A-F (十六进制) 的字母。 选择 “确定” 以保存设置并关闭对话框

PinRules 属性。

  1. 关闭组策略管理编辑器以保存设置
  2. 企业证书固定规则 GPO 链接到包含要配置的设备的 OU

其他引脚规则日志记录

为了帮助构造证书固定规则,可以在证书链配置注册表项下配置 PinRulesLogDir 设置,以包含用于记录固定规则的父目录。

名称
HKLM\SOFTWARE\Microsoft\Cryptography\OID\EncodingType0\CertDllCreateCertificateChainEngine\Config
名称 PinRulesLogDir
Windows 写入其他 pin 规则日志的父目录
数据类型 REG_SZ

固定规则日志文件夹的权限

Windows 写入其他 pin 规则日志的文件夹必须具有权限,如此所有的用户和应用程序都具有完全访问权限。 可以从提升的命令提示符运行以下命令,以获得适当的权限。

set PinRulesLogDir=c:\PinRulesLog
mkdir %PinRulesLogDir%
icacls %PinRulesLogDir% /grant *S-1-15-2-1:(OI)(CI)(F)
icacls %PinRulesLogDir% /grant *S-1-1-0:(OI)(CI)(F)
icacls %PinRulesLogDir% /grant *S-1-5-12:(OI)(CI)(F)
icacls %PinRulesLogDir% /inheritance:e /setintegritylevel (OI)(CI)L

当应用程序验证包含与服务器证书中的 DNS 名称匹配的服务器名称的 TLS/SSL 证书链时,Windows 会将包含服务器链中所有证书的 .p7b 文件写入三个子文件夹之一:

  • AdminPinRules:匹配企业证书固定规则中的站点
  • AutoUpdatePinRules:匹配 Microsoft 管理的证书固定规则中的站点
  • NoPinRules:与证书固定规则中的任何站点都不匹配

输出文件名由根的 SHA1 指纹的前八个 ASCII 十六进制数字组成,后跟服务器名称。 例如:

  • D4DE20D0_xsi.outlook.com.p7b
  • DE28F4A4_www.yammer.com.p7b

如果存在企业证书固定规则或 Microsoft 证书固定规则不匹配,则 Windows 会将 .p7b 文件写入 MismatchPinRules 子文件夹。 如果 pin 规则已到期,Windows 会将 .p7b 写入 ExpiredPinRules 子文件夹。

在 XML 中表示日期

pin 规则 xml 文件中的许多属性是日期。
这些日期必须正确进行格式设置并以 UTC 表示。
可以使用 Windows PowerShell 来规定这些日期的格式。
然后可以复制 cmdlet 的输出并将其粘贴到 XML 文件。

表示日期。

为简单起见,可以截断小数点 (.) 及其后面的数字。 但是,请务必将大写的“Z”追加到 XML 日期字符串的末尾。

2015-05-11T07:00:00.2655691Z
2015-05-11T07:00:00Z

转换 XML 日期

还可以使用 Windows PowerShell 验证 XML 日期并将其转换为人工可读日期,以验证其是否为正确的日期。

转换 XML 日期。

以 XML 表示持续时间

一些元素可以配置为使用持续时间而非日期。 必须将持续时间表示为 XML 时间跨度数据类型。 可以使用 Windows PowerShell 正确设置持续时间(时间跨度)的格式并进行验证,然后将其复制并粘贴到 XML 文件中。

表示持续时间。

转换 XML 持续时间

可以将 XML 格式的时间跨度转换为可读取的时间跨度变量。

转换 XML 持续时间。

证书信任列表 XML 架构定义 (XSD)

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="PinRules">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="PinRule" maxOccurs="unbounded" minOccurs="1">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Certificate" maxOccurs="unbounded" minOccurs="0">
                <xs:complexType>
                  <xs:simpleContent>
                    <xs:extension base="xs:string">
                      <xs:attribute type="xs:dateTime" name="EndDate" use="optional"/>
                      <xs:attribute type="xs:string" name="File" use="optional"/>
                      <xs:attribute type="xs:string" name="Directory" use="optional"/>
                      <xs:attribute type="xs:base64Binary" name="Base64" use="optional"/>
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
              </xs:element>
              <xs:element name="Site" maxOccurs="unbounded" minOccurs="1">
                <xs:complexType>
                  <xs:simpleContent>
                    <xs:extension base="xs:string">
                      <xs:attribute type="xs:string" name="Domain"/>
                      <xs:attribute type="xs:boolean" name="AllSubdomains" use="optional" default="false"/>
                    </xs:extension>
                  </xs:simpleContent>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
            <xs:attribute type="xs:string" name="Name"/>
            <xs:attribute name="Error" use="optional" default="None">
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:enumeration value ="Revoked"/>
                  <xs:enumeration value ="InvalidName"/>
                  <xs:enumeration value ="None"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:attribute>
            <xs:attribute type="xs:boolean" name="Log" use="optional" default="true"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
      <xs:attribute type="xs:duration" name="Duration" use="optional"/>
      <xs:attribute type="xs:duration" name="LogDuration" use="optional"/>
      <xs:attribute type="xs:dateTime" name="NextUpdate" use="optional"/>
      <xs:attribute type="xs:dateTime" name="LogEndDate" use="optional"/>
      <xs:attribute type="xs:string" name="ListIdentifier" use="optional"/>
    </xs:complexType>
  </xs:element>
</xs:schema>