将 SSLOptions.VerifyCertificate 设置为 True,服务器会向每个传入的客户端索要证书,并验证其出示的证书链。该验证确认客户端证书链是受信任的,但完全无法说明该客户端证书自颁发以来是否已被吊销。
在以证书作为凭据的场景中,这个缺口很重要:笔记本电脑丢失或员工离职后,颁发给他们的证书虽已被吊销,但在过期之前仍然能够在您的服务器上打开会话。只有在明确要求时,才会通过 SSLOptions.SChannel_Options.Revocation 检查吊销状态。
这些吊销设置是在验证客户端证书的过程中读取的,因此除非 SSLOptions.VerifyCertificate 为 True,否则它们不起任何作用,正是该属性使服务器首先向客户端索要证书。至于完全不出示证书的客户端是被拒绝还是被放行,则是另一项独立的决定,由 SSLOptions.VerifyCertificate_Options.FailIfNoCertificate 决定。
oServer.SSL := True;
oServer.SSLOptions.IOHandler := iohSChannel;
oServer.SSLOptions.VerifyCertificate := True;
oServer.SSLOptions.VerifyCertificate_Options.FailIfNoCertificate := True;
oServer.SSLOptions.SChannel_Options.Revocation.Check := scrcChainExcludeRoot;
吊销状态是在构建证书链的过程中获取的,这意味着握手期间会连接客户端证书中指定的 CRL 分发点或 OCSP 响应方。这正是该检查默认关闭的原因:它会为服务器接受的每个连接都增加一次对外请求。
用于选择对客户端证书链中的哪些部分查询吊销状态。
| scrcDisabled | 默认值。不获取任何吊销状态,也不要求提供吊销状态。 |
| scrcEndCertificate | 仅检查客户端证书本身。开销最小的选项,每个连接只查询一次。 |
| scrcChainExcludeRoot | 检查客户端证书以及颁发该证书的中间证书,但不检查根证书。这是通常的选择,因为颁发您客户端证书的 CA 的根证书很少为自身发布 CRL。 |
| scrcChain | 包括根证书在内的整个证书链。 |
整个吊销信息获取过程所允许的毫秒数,而不是每个 URL 的毫秒数,因此不作应答的响应方无法让服务器在等待中拖住握手过程。默认值为 5000。值为零时将沿用 Windows 的默认值,而该值可能长得多。
为 True 时,仅使用 Windows 已缓存的吊销数据,握手过程绝不会访问网络,因此传入的连接永远不会被响应方延迟。此时若缓存为空,吊销状态将无法确定,该情况由 IgnoreNoRevocationCheck 决定。默认值为 False。
决定无法连接响应方时的处理方式。默认值为 True,即接受该客户端证书,这就是软失败行为。将其设置为 False 则改为拒绝。拒绝更为严格,但这会使每个新连接都依赖于服务器能否连接到响应方,因此响应方一旦中断,您的所有客户端也会随之中断。
决定当客户端证书完全没有发布 CRL 分发点和 OCSP 响应方,因而无法确定其状态时的处理方式。默认值为 True,即接受该证书。由内部 CA 颁发的证书经常不携带任何吊销信息,因此只有在确认您发放给客户端的每一张证书都发布了吊销信息之后,才应将其设置为 False。
这两个 Ignore 属性都绝不会接受已确认被吊销的证书。这种结果始终会被拒绝,握手随之失败。
当证书链检查拒绝某个客户端时,原因为下列值之一:
| ecCryptRevoked | 客户端证书已被其颁发者吊销。始终拒绝。 |
| ecCryptRevocationOffline | 无法连接响应方。仅当 IgnoreRevocationOffline 为 False 时才拒绝。 |
| ecCryptNoRevocationCheck | 客户端证书未发布任何吊销信息。仅当 IgnoreNoRevocationCheck 为 False 时才拒绝。 |
将 SSLOptions.Preset 设置为 tlspSecureDefaults,会在服务器端把该检查启用为 scrcChainExcludeRoot,与同一预设在客户端已经应用的设置保持一致,同时保留这两项软失败设置,因此原本可以接入的客户端仍然可以接入。如果您在应用该预设之前已自行选择了检查范围,则该范围保持不变。
oServer.SSLOptions.Preset := tlspSecureDefaults;