问题描述
我正在尝试在我的 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