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
我正在尝试在我的 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));
这是我的管道:
在 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