Unsecure Origin (Heroku App) 呈现 NodeJS 的 Web Cryptography API require() 未定义。有什么解决方法吗?

Unsecure Origin (Heroku App) renders NodeJS's Web Cryptography API require() undefined. Is there any workaround?

我正在尝试在我的 Herokuapp Nodejs 服务器上实施实验性 Web 密码学 api (subtlecrypto),以便加密来自 gitpages -> herokuapp 获取请求的数据,将敏感信息隐藏在浏览器控制台网络选项卡,然后解密 client-side.

我正在关注 https://www.nearform.com/blog/implementing-the-web-cryptography-api-for-node-js-core/ 作为参考。

不幸的是,我尝试从 subtlecrypto 调用的任何方法都以未定义的形式返回,喷出错误,例如

TypeError: Cannot read property 'encrypt' of undefined

当我尝试 运行

const cipher = await SubtleCrypto.encrypt({ name: 'AES-CBC', iv }, ckey, ec.encode('data'));

ReferenceError: getRandomValues is not defined

当我尝试定义

const iv = getRandomValues(new Uint8Array(16));

线程似乎指出了问题所在(chromium 认为 origin 不安全,禁止使用 subtlecrypto),但未能为我自己的环境提供解决方案。

这是我的管道:

在 github 页面(启用 Enforce HTTPS)中,此 .js 文件在 html 页面中 linked,向我的 Heroku 应用程序发送获取请求

var apikey, dir, documentdir;

function makeid(length) {
    var result           = '';
    var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    var charactersLength = characters.length;
    for ( var i = 0; i < length; i++ ) {result += characters.charAt(Math.floor(Math.random() * charactersLength));}return result;
}

var tag=makeid(32);

document.addEventListener("adobe_dc_view_sdk.ready", function () {
    fetch("https://myapp.herokuapp.com/api/NotTheActualLink", {headers: {"header1" : tag, "header2" : aString}} )
        .then((response) => response.json())
        .then((data) => {
            window.crypto.subtle.importKey(
                "raw", //can be "jwk" or "raw"
                {   //this is an example jwk key, "raw" would be an ArrayBuffer
                    kty: "oct",
                    k: tag,
                    alg: "A256CBC",
                    ext: true,
                },
                {   //this is the algorithm options
                    name: "AES-CBC",
                },
                false, //whether the key is extractable (i.e. can be used in exportKey)
                ["encrypt", "decrypt"] //can be "encrypt", "decrypt", "wrapKey", or "unwrapKey"
            )
            .then(function(key){
                window.crypto.subtle.decrypt(
                    {
                        name: "AES-CBC",
                        iv: data.vi, //The initialization vector you used to encrypt
                    },
                    key, //from generateKey or importKey above
                    data.iv //ArrayBuffer of the data
                )
                .then(function(decrypted){
                    //returns an ArrayBuffer containing the decrypted data
                    console.log(new Uint8Array(decrypted));
    
                    apikey = data.api;
                    doccy = data.docname;
                    dir = data.dir;
                })
            })
            .catch(function(err){
                console.error(err);
            });
        })
        .then(function () {
            var adobeDCView = new AdobeDC.View({ clientId: apikey, divId: "adobe-dc-view" });
            adobeDCView.previewFile({
                content: { location: { url: dir } },
                metaData: { fileName: doccy }
            }, { embedMode: "IN_LINE", showDownloadPDF: false, showPrintPDF: false });
        });
});

当应用程序检测到对 api/NotTheActualLink 的请求时,它会读取我发送的自定义 headers 以获取用于生成加密密钥 (ckey) 的随机字符串和我希望它用 (id) 响应的文档。

const express = require("express");
const app = express();

const SubtleCrypto = require("crypto").webcrypto;

const { MongoClient } = require("mongodb");

const uri = process.env.MONGODB_URI;
const origin = process.env.ORIGIN_URL;
const db = process.env.DB_NAME;
const col = process.env.COL_NAME;
const path = process.env.API_PATH;
const xheader1 = process.env.X_HEADER_1;
const xheader2 = process.env.X_HEADER_2;

app.options(path, async function (req, res, next) {
  res.header('Access-Control-Allow-Origin', origin);
  res.header('Access-Control-Allow-Methods', 'GET,OPTIONS');
  res.header('Access-Control-Allow-Headers', xheader1.concat(", ",xheader2));
  next();
});

app.get(path, async function (req, res) {
  const client = new MongoClient(uri, { useUnifiedTopology: true });
  res.header('Access-Control-Allow-Origin', origin);
  res.header('Access-Control-Allow-Methods', 'GET,OPTIONS');
  res.header('Access-Control-Allow-Headers', xheader1.concat(", ",xheader2));

  try {
    await client.connect();
    console.log("isSecureContext= "+app.isSecureContext);
    var ckey = req.header(xheader1);
    var id = req.header(xheader2);
    console.log("key= "+ckey);
    console.log("id= "+id);

    const database = client.db(db);
    const collection = database.collection(col);
    const query = { docId: id };
    const cursor = await collection.findOne(query);
    const result = cursor;

    const ec = new TextEncoder();
    const algorithm = 'aes-256-cbc';
    const iv = getRandomValues(new Uint8Array(16));
    const cipher = await SubtleCrypto.encrypt({ name: 'AES-CBC', iv }, ckey, ec.encode(result));
    const data = await SubtleCrypto.encrypt({ name: 'AES-CBC', iv }, ckey, cipher);
  
    var response =
    {
      iv: iv.toString('hex'),
      dater: data.toString('hex')
    };

    return res.json(response);

  } catch (err) {
    console.log(err);
  }
  finally {
    await client.close();
  }
});

app.listen(process.env.PORT || 3000,
  () => console.log("Server is running..."));

它从那里建立到我的 MongoDB 集群的连接(link: mongodb+srv://yada:yadayada@foo.bar.mongodb.net/mydatabase ?retryWrites=true&w=majority) 并检索包含我要加密并发送到客户端浏览器的数据的文档。或者至少那是它应该做的。

我只是不明白这些交互中的哪一个使连接不安全,禁用了 subtlecrypto。

我可以做些什么来确保源安全?

此外,console.log("isSecureContext= "+app.isSecureContext); 似乎没有针对原点,但 window.isSecureContext 也不起作用,因为该应用程序(只是上面的 .js 文件)不是 运行在浏览器中 window.

我得到了一位朋友的帮助,但我明白了! 来源是安全的,从一开始就不是问题。服务器的Nodejs版本确实是问题

WebCrypto 仅在节点 v15.x 中添加,因为 Heroku 是 运行 LTS 版本 (14.5.5),只需要更新!

查看本指南了解更多详情: https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version