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

问题描述

我正在尝试在我的 Herokuapp Nodejs 服务器上实现实验性的 Web 加密 api(subtlecrypto),以便对来自 gitpages 的数据进行加密 -> herokuapp fetch 请求,从浏览器控制台网络选项卡中隐藏敏感信息到那时解密客户端。

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

不幸的是,我尝试从微妙加密中调用的任何方法都返回为未定义的、喷出错误的,例如

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));

TypeError,'digest' of undefined,in development environment 线程似乎指出了问题(chromium 认为来源不安全,禁止使用微妙的加密),但未能为我自己的环境提供解决方案。

这是我的管道:

在 github 页面(启用强制 HTTPS)中,这个 .js 文件链接一个 html 页面中,向我的 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 的请求时,它会读取我发送的自定义标头,以获取用于生成加密密钥 (ckey) 的随机字符串和我希望它响应的文档 ID与(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,res) {
  const client = new MongoClient(uri,{ useUnifiedTopology: true });
  res.header('Access-Control-Allow-Origin',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',ec.encode(result));
    const data = await SubtleCrypto.encrypt({ name: 'AES-CBC',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 集群的连接(链接:mongodb+srv://yada:[email protected]/mydatabase?retryWrites=true&w=majority)并检索包含我的数据的文档想要加密并发送到客户端浏览器。或者至少这是它应该做的。

我只是无法理解这些交互中的哪一个使连接不安全,禁用了微妙的加密。

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

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

解决方法

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

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

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