node.js - Express Handlebars 不会渲染数据

标签 node.js express mongoose server-side-rendering express-handlebars

我正在使用 Express-Handlebars 模板引擎来使用 NodeJS 和 Express。

Handlebars 在尝试渲染模板时抛出以下错误:

Handlebars: Access has been denied to resolve the property "username" because it is not an "own property" of its parent. You can add a runtime option to disable the check or this warning: See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details

根据上面的链接:

From version 4.6.0 on, Handlebars forbids accessing prototype properties and methods of the context object by default. The reason are various security issues that arise from this possibility.

我的 app.js 包含以下内容:

const exphbs = require('express-handlebars');
const express = require('express');
// Init Express
const app = express();
// VIEW ENGINE
app.engine('handlebars', exphbs({
  defaultLayout: 'main'
}));
app.set('view engine', 'handlebars');

我的路由文件通过 Mongoose 从 MongoDB 获取:

//@GET - View
router.get('/', authMiddleware, (req, res, next) => {
  // Mongoose
  Model.find({ user: req.user._id })
    .sort({ date: -1 })
    .then(model => {
      res.render('/overview', { model: model })
    })
    .catch(err => {
      if (err) throw err;
      req.flash('error_msg', 'No Model Found');
    })

})

模型是对象数组

这个问题是在我开始尝试添加 Handlebars 助手之后才开始发生的。我已删除助手并恢复到原始配置设置(上面),但无济于事。我尝试删除 node_modules 文件夹并重新安装 npm。

发送的是一个对象数组,我尝试使用 {{#each model}} 帮助器循环对象的属性,并通过每个中的 {{prop1}} 引用各个属性。

根据 Handlebars 的说法,默认情况下禁用 proto 属性是 false,并且此更改不应破坏任何内容。

我的问题:

  1. 我是否错误地将数据发送到 Handlebars ?如果是这样,将数据发送到express-handlebars模板进行渲染的正确方法是什么(不让我的服务器暴露于安全漏洞)?

提前谢谢您。

最佳答案

当我升级 Handlebars 套件时,我遇到了同样的问题。为了尽快让您的系统恢复在线状态,请删除 package.json 中的 handbars 条目,然后在其位置插入此行。

"handlebars": "4.5.3",

从版本 4.6.0 开始,Handlebars 默认禁止访问上下文对象的原型(prototype)属性和方法。这与此处描述的安全问题有关: https://mahmoudsec.blogspot.com/2019/04/handlebars-template-injection-and-rce.html

引用 https://github.com/wycats/handlebars.js/issues/1642

上述 URL 中的示例显示了 Mongoose 响应转换为 JSON 的情况:

app.get('/test', function (_req, res) {
    Kitten.find({}).then(kittens => {
        res.render('test.hbs', {
            kittens: kittens.map(kitten => kitten.toJSON())
        })
    })
});

如果您确定只有受信任的开发人员且没有最终用户有权访问 Handlebars 模板,则可以通过安装以下软件包来允许原型(prototype)访问:

npm install @handlebars/allow-prototype-access

下面是它的使用示例:

const express = require('express');
const Handlebars = require('handlebars')
const expressHandlebars = require('express-handlebars');
const {allowInsecurePrototypeAccess} = require('@handlebars/allow-prototype-access')

const app = express();

app.engine('handlebars', expressHandlebars({
    handlebars: allowInsecurePrototypeAccess(Handlebars)
}));
app.set('view engine', 'handlebars');
...

另一种选择是使用 mongoose .lean() 函数。这样做的好处是比传统的 Mongoose 查询快得多。但它也有一些缺点。默认情况下,Mongoose 查询返回 Mongoose Document 类的实例。这些对象包含大量用于更改跟踪的内部状态,并具有其他方法,例如 .save()。启用精简选项告诉 Mongoose 跳过实例化完整的 Mongoose 文档,只返回纯 JavaScript 对象。

关于node.js - Express Handlebars 不会渲染数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59753149/

相关文章:

javascript - ExpressJS 上的异步函数

node.js - 为什么很多 Node.js Web 框架都是基于 Express 构建的?为什么 Express 不实现这些功能?

javascript - 保持原有IP地址的情况下进行跨域请求

linux - 无法在 Manjaro 中连接 MongoDB 服务器,退出代码为 100 的错误

node.js - MongoDB/Mongoose 在特定日期查询?

node.js - 我可以在 prisma 的 connectOrCreate 中使用 "AND"吗?

javascript - Node.js child_process exec 的标准输出被缩短

mysql - 我如何使用 sequelize ORM 将列定义为 tinyint(4)

express - NestJS - 如何使用 TypeOrm 正确更新

node.js - 模型定义之前定义的中间件,级联删除失败,出现中间件被绕过