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

JavaScript验证服务器公钥哈希的可行性及证书链验证方案探讨

Certificate Validation via JavaScript: Solutions & Limitations

Great question, and I’m sorry to hear about those rough experiences with certificate hijacking—those are exactly the kind of edge cases that expose gaps in how we trust pre-installed certs and signed software. Let’s break down your questions and the feasible options available:

Can JavaScript verify a server’s public key or let users check its hash?

Yes, but with significant browser-specific limitations, plus some workarounds for cross-browser support:

1. Firefox’s getSecurityInfo (Direct, but Firefox-Only)

You’re right that Firefox’s non-standard navigator.getSecurityInfo() API is the only built-in way for JavaScript to directly access certificate chain details, including public key hashes. Here’s a quick example to fetch the server’s public key SHA-256 hash:

async function fetchServerPublicKeyHash() {
  try {
    // Only works in Firefox, requires HTTPS
    const securityInfo = await navigator.getSecurityInfo();
    const serverCert = securityInfo.certificates[0]; // First cert is the server's own
    
    // Export public key as raw SPKI format
    const publicKeyRaw = await serverCert.publicKey.export({ type: 'spki', format: 'raw' });
    // Generate SHA-256 hash
    const hashBuffer = await crypto.subtle.digest('SHA-256', publicKeyRaw);
    const hashHex = Array.from(new Uint8Array(hashBuffer))
      .map(byte => byte.toString(16).padStart(2, '0'))
      .join('');
    
    console.log('Server Public Key SHA-256:', hashHex);
    return hashHex;
  } catch (err) {
    console.error('Failed to retrieve security info:', err);
    return null;
  }
}

Caveats: This is not a web standard, so it won’t work in Chrome, Edge, Safari, etc. Mozilla could also modify or remove it in future updates.

2. Cross-Browser Workarounds

Since standard JavaScript intentionally restricts low-level key access (to prevent malicious scripts from abusing certificate data), you’ll need application-layer hacks:

  • Pre-stored Trusted Hashes + Backend Validation: Embed a hardcoded list of trusted server public key hashes in your frontend. Then, add a backend endpoint (e.g., /.well-known/trusted-key-hash) that returns the current server’s public key hash. Your frontend can fetch this value and compare it to the pre-stored list.
    Note: This only works if you trust that the backend hasn’t been compromised, and it won’t detect cases where a malicious root cert is forcing a man-in-the-middle attack (since the MITM would also tamper with the endpoint’s response).

  • Manual User Verification: Display the server’s public key hash prominently on critical pages (e.g., login, banking transactions) and guide users to manually verify it via their browser’s certificate viewer:

    1. Click the lock icon in your address bar
    2. Select "Certificate" → "Details"
    3. Navigate to "Public Key" → "Fingerprint"
    4. Compare this value to the one shown on our page

    This is the most reliable cross-browser method, but it’s not user-friendly and requires technical literacy.

  • Browser Extensions: Build a browser extension that accesses browser-specific certificate APIs (e.g., Chrome’s chrome.webRequest to inspect certificates). The extension can auto-compare the server’s key hash to a trusted list and alert users to mismatches. However, this requires users to install the extension, which adds friction.

Can we verify the certificate chain has no malicious tampering via application-layer JS?

Unfortunately, this is extremely tricky for two main reasons:

  1. Browser Security Restrictions: Standard JS can’t access the full certificate chain or metadata about whether a root cert is pre-installed vs. user-added. Browsers hide this to prevent malicious scripts from fingerprinting users or exploiting trust gaps.
  2. Pre-Installed Malicious Certs: If an attacker has planted a trusted root cert (like the Fortigate case), the browser will treat the MITM’s certificate as valid, and JS has no way to detect this unless you can pre-validate the entire expected certificate chain.

Partial Solution (Firefox-Only)

Using getSecurityInfo, you can fetch the full certificate chain and compare each cert’s hash to a pre-stored list of trusted CAs/roots. If any cert in the chain isn’t on your trusted list, you can warn the user. But again, this only works in Firefox and requires maintaining an up-to-date list of trusted certs.


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 10:12:38