跳到主要内容
ecdsa.com
WebCryptoWebCrypto

错误信息

TypeError: Cannot read properties of undefined (reading 'digest')

也可能输出为

  • TypeError: Cannot read properties of undefined (reading 'importKey')
  • TypeError: can't access property "digest", crypto.subtle is undefined
  • TypeError: undefined is not an object (evaluating 'crypto.subtle.digest')

这段文字是引擎通用的 TypeError:Chromium/V8 为“Cannot read properties of undefined (reading 'digest')”,Firefox 为“can't access property \"digest\", crypto.subtle is undefined”,Safari/WebKit 为“undefined is not an object (evaluating 'crypto.subtle.digest')”。其中的方法名取决于第一次调用的方法(`importKey`、`sign`、`generateKey` 等)。

WebCrypto — window.crypto.subtle is undefined outside a secure context (Chromium / Firefox / WebKit)

含义

这个页面上不存在 `crypto.subtle`,因此对它的第一次调用就会报出一个笼统的“undefined”TypeError。浏览器只在安全上下文中提供 `SubtleCrypto`:通过 HTTPS 提供的页面、来自 `http://localhost` / `127.0.0.1` 的页面,或者 `file:` URL。同样的代码在你自己机器上的 localhost 中能正常运行,但只要通过普通 HTTP、用另一个主机名或 IP 地址打开页面,就会出错。`crypto.getRandomValues` 仍然可用,所以这个故障看起来像是只影响部分功能。

原因

修复方法

  1. 1.

    检测这种情况,并给出明确的错误提示

    在使用 WebCrypto 之前检查 `window.isSecureContext`。不要悄悄回退到用 JavaScript 实现的密码学 polyfill——没有 TLS,页面本身的完整性本来就无法保证。

    js
    if (!window.isSecureContext || !globalThis.crypto?.subtle) {
      throw new Error("WebCrypto needs HTTPS (or http://localhost). Current origin: " + location.origin);
    }
    const digest = await crypto.subtle.digest("SHA-256", data);
  2. 2.

    通过 HTTPS 提供页面

    在每个环境中都使用 TLS,包括你从其他设备访问的开发服务器;mkcert 等工具可以创建本地受信任的证书。

    bash
    # Local HTTPS for a dev server reachable from other devices
    mkcert -install
    mkcert dev.example.test 192.168.1.20 localhost
    # Vite: server.https = { key: fs.readFileSync("dev.example.test+2-key.pem"), cert: fs.readFileSync("dev.example.test+2.pem") }

相关错误

浏览完整的签名错误库