PAYATHON 2026

TWebBrowser.Silent = TRUE 后为何仍弹出证书警告?

排障赵师傅

结论

TWebBrowser.Silent := True 不会关闭证书验证,也不会改变证书吊销检查策略。仅设置 Silent,无法保证这类安全提示不再出现。

要通过代码处理,应在浏览器宿主中接入 IHttpSecurity.OnSecurityProblem,由程序决定遇到证书问题时中止还是继续。实现前要先确定处理策略:不弹窗并中止访问,还是不弹窗且继续访问。

对于分发到大量客户端的程序,应优先修复证书或吊销信息访问问题。确实需要静默处理时,再实现宿主接口。

为什么设置 Silent 后仍会提示

TWebBrowser 封装的是 IE WebBrowser ActiveX 控件。页面导航和安全检查还涉及 MSHTML、URLMon、WinINet 及 Windows 证书验证组件。

Silent 是浏览器的界面控制属性,不能替代证书错误处理。官方文档说明,该属性会委托给顶层框架处理,没有框架时可能返回 E_FAIL。排查时,应确认属性是否设置成功,以及弹窗是否来自同一个浏览器实例。参考:IWebBrowser2::Silent

“无法获取此站点安全证书的吊销信息”表示客户端无法完成相应的吊销状态检查,不能据此认定证书已经被吊销。WinINet 为这两种情况定义了不同的错误码,需要分别处理:

  • ERROR_INTERNET_SEC_CERT_REV_FAILED,值为 12057,表示吊销检查失败。
  • ERROR_INTERNET_SEC_CERT_REVOKED,值为 12170,表示证书已经被吊销。

参考:WinINet 错误码

即使代码传入的是 http://...,后续重定向、框架或页面资源仍可能访问 HTTPS 地址,触发证书检查。

为什么只有部分计算机会出现

先在出现问题的客户端上检查实际证书链,以及证书中指定的 CRL 或 OCSP 地址。

客户端之间可能存在以下差异:

  • 部分网络无法访问吊销信息服务,例如访问被代理、防火墙或 DNS 配置阻断。
  • 一些客户端已有有效的吊销信息缓存,另一些需要联网获取。
  • 客户端使用的证书链、吊销检查策略或系统环境不同。

仅凭提示文字无法确定具体原因。Windows 证书链验证涉及吊销信息获取、缓存和超时处理,因此,同一站点在不同客户端上可能得到不同结果。参考:CertGetCertificateChain

如果能够控制服务端,应先确认其证书链配置正确,并确保客户端网络可以访问相关吊销信息服务。解决这些问题可以消除触发提示的原因,无须逐台修改 Internet Options。

通过宿主接口静默处理

IHttpSecurity.OnSecurityProblem 允许程序接管相关安全问题。桌面版接口文档规定了以下返回值:

返回值含义
E_ABORT中止下载
S_FALSE显示警告对话框
RPC_E_RETRY继续或重试下载

在此回调中返回 S_FALSE 会要求显示警告,不能用它禁止弹窗。桌面版接口继续处理时应按文档返回 RPC_E_RETRY,不能照搬 Windows CE 示例中的 S_OK。参考:IHttpSecurity::OnSecurityProblem

必须通过浏览器宿主的服务查询机制,向 MSHTML 提供这些接口。仅在窗体中声明一个同名方法,浏览器不会自动调用它。参考:IHttpSecurity

示例:不弹窗,并中止有证书问题的访问

以下示例使用 Delphi 7 风格的派生控件接入接口。对进入该回调的安全问题,示例统一返回 E_ABORT,相应请求会失败,页面也不保证加载成功。

unit QuietWebBrowser;

interface

uses
  Windows, ActiveX, UrlMon, SHDocVw;

type
  TQuietWebBrowser = class(TWebBrowser, IServiceProvider,
    IWindowForBindingUI, IHttpSecurity)
  protected
    function QueryService(const rsid, iid: TGUID;
      out Obj): HRESULT; stdcall;

    function GetWindow(const guidReason: TGUID;
      out wnd): HRESULT; stdcall;

    function OnSecurityProblem(
      dwProblem: DWORD): HRESULT; stdcall;
  end;

implementation

function TQuietWebBrowser.QueryService(
  const rsid, iid: TGUID; out Obj): HRESULT;
begin
  Pointer(Obj) := nil;

  if IsEqualGUID(iid, IID_IHttpSecurity) or
     IsEqualGUID(iid, IID_IWindowForBindingUI) then
    Result := QueryInterface(iid, Obj)
  else
    Result := E_NOINTERFACE;
end;

function TQuietWebBrowser.GetWindow(
  const guidReason: TGUID; out wnd): HRESULT;
begin
  HWND(wnd) := Handle;
  Result := S_OK;
end;

function TQuietWebBrowser.OnSecurityProblem(
  dwProblem: DWORD): HRESULT;
begin
  // 在这里记录 dwProblem,便于定位客户端差异。
  Result := E_ABORT;
end;

end.

使用时,必须实际创建这个派生控件。例如,先在窗体中增加字段 FBrowser: TQuietWebBrowser,再创建实例:

procedure TForm1.FormCreate(Sender: TObject);
begin
  FBrowser := TQuietWebBrowser.Create(Self);
  FBrowser.Parent := Self;
  FBrowser.Align := alClient;
  FBrowser.Silent := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  FBrowser.Navigate('https://your-server.example/');
end;

仅把现有 WebBrowser1 强制转换成 TQuietWebBrowser,不会改变其实例类型,也不会安装这些接口。

不同 Delphi 版本的封装可能已经实现了 QueryService,或提供了对应的扩展事件。如果已有服务实现,应将上述分支合并进去,保留其他服务的处理。方法签名和是否需要 override,以所用版本的声明为准。

如果必须继续加载

如果业务明确允许在“吊销状态暂时无法确认”时继续访问,可以在经过验证的处理分支中返回 RPC_E_RETRY。这一处理不能用于所有证书问题,使用时应满足以下条件:

  1. 在出现问题的计算机上记录 dwProblem,确认实际错误类型,不能只根据弹窗文字假定它一定是 12057。
  2. 例外只适用于预先限定并验证的目标站点,同时要考虑重定向、框架和其他 HTTPS 资源。
  3. 对证书已吊销、主机名不匹配、过期或不受信任等其他错误,仍应中止访问。

OnSecurityProblem 的参数只有错误码,无法单凭它核验当前请求的 URL 和证书,也不能直接用 LocationURL 判断当前失败请求的身份。

返回 RPC_E_RETRY 意味着接受相关安全问题并继续访问,会削弱对应检查的保护,也不会修复证书或网络故障。微软明确要求谨慎使用这一返回值。参考:OnSecurityProblem 安全说明

部署前需要确认的事项

应在实际出现弹窗的环境中,验证 QueryService 和 OnSecurityProblem 是否被调用。不同 IE/MSHTML 版本及安全提示路径可能存在差异。如果回调没有触发,仅增加这些方法不能说明问题已经解决。

这套接口只能处理进入相应宿主回调的安全问题,无法保证屏蔽所有浏览器或系统对话框。对于数千客户端的部署,至少要验证正常证书、吊销信息不可达、证书已吊销,以及重定向场景。

不宜为了单个控件直接改写用户级 Internet Options 或关闭全局吊销检查。这些修改会影响其他使用相关设置的程序,也可能受到组织策略约束。

备注:内容仅供参考。