Manillares: se ha denegado el acceso para resolver la propiedad "desde" porque no es una "propiedad propia" de su padre

15

Estoy usando un backend Nodejs con representación del lado del servidor usando manillares. Después de leer una docmatriz de objetos del manillar, que contiene "contenido" y "de" clave. Sin embargo, cuando intento usar #eachpara recorrer la matriz de objetos, aparece el error "Manillares: acceso denegado para resolver la propiedad" desde "porque no es una" propiedad propia "de su padre".

Intenté console.log () los datos que obtuve en la matriz de documentos y todo parece estar bien.

Para alguna perspectiva, esta es la consulta de mangosta,
agregué el objeto doc como una clave dentro de los argumentos res.render.

Confession.find()
  .sort({date: -1})
  .then(function(doc){
    for(var i=0; i < doc.length; i++){
      //Check whether sender is anonymous
      if (doc[i].from === "" || doc[i].from == null){
        doc[i].from = "Anonymous";
      }

      //Add an extra JSON Field for formatted date
      doc[i].formattedDate = formatTime(doc[i].date);
    }
    res.render('index', {title: 'Confession Box', success:req.session.success, errors: req.session.errors, confession: doc});
    req.session.errors = null;
    req.session.success = null;
  });

Esta es la parte del archivo .hbs que estoy intentando recorrer:

 {{#each confession}}
    <div class="uk-card uk-card-default uk-card-body uk-margin uk-align-center uk-width-1-2@m" >
        <div class="uk-text-bold">Message: </div>
        <div>{{this.content}}</div>
        <div>From: {{this.from}}</div>
        <div>Posted: {{this.formattedDate}}</div>
    </div>
    {{/each}}

Lee Boon Kong
fuente

Respuestas:

25

resuelvo este problema instalando una dependencia de desarrollo para el manillar

npm i -D [email protected]

Masón
fuente
Wow esto funcionó, ¿por qué está pasando esto? Actualmente estoy usando express-handlebars (3.1.0) que configuré como motor de renderizado en mi aplicación express.
Lee Boon Kong
Sospecho que esto estaba sucediendo en la versión más nueva del manillar debido a algunas restricciones, pero no sé cómo trabajar en estas restricciones.
Lee Boon Kong
Bueno, el problema radica entre el complemento express que admite manillares, pero una vez que el manillar 4.5.0 se guarde para usarlo como el motor principal de su interfaz, hágamelo saber al comentar sobre esto.
Mason
Esto no está funcionando. Todavía tengo el mismo problema después de ejecutar npm i -D [email protected]
Deepak Thakur
La respuesta correcta está aquí github.com/wycats/handlebars.js/issues/1642
Deepak Thakur
13

Si usa mangosta, este problema puede resolverse usando .lean () para obtener un objeto json (en lugar de una mangosta):

dbName.find({}).lean()
  // execute query
  .exec(function(error, body) {
     //Some code
  });
Billeh
fuente
3
¡Dios te bendiga! Salvavidas!
Nick Thenick
1
No hay problema, me alegro de que haya ayudado.
Billeh
2
Ojalá pudiera votar esta respuesta más de una vez ... jaja ¡Muchas gracias!
Abdus
7

Hoy tengo la misma advertencia del manillar y la vista está vacía. A continuación se muestra cómo arreglé eso:

//  * USERS PAGE
// @description        users route
// @returns           ../views/users.hbs
router.get('/users', async (req, res) => {
  // get all items from db collection
  const collection = 'User'
  await dbFindAllDocs(collection) // <=> wrapper for Model.find() ...
    .then(documents => {
      // create context Object with 'usersDocuments' key
      const context = {
        usersDocuments: documents.map(document => {
          return {
            name: document.name,
            location: document.location
          }
        })
      }
      // rendering usersDocuments from context Object
      res.render('users', {
        usersDocuments: context.usersDocuments
      })
    })
    .catch(error => res.status(500).send(error))
})

el archivo users.hbs

<ul>
{{#each usersDocuments}}
<li>name: {{this.name}} location: {{this.location}}</li>
{{/each}}    
</ul>

Crear un nuevo Objeto completo contextcon sus propias propiedades y luego pasarlo a la función de renderizado solucionará el problema ...

Nota:

Cuando no creamos un nuevo Objeto, es fácil exponer accidentalmente información confidencial, o información que podría comprometer la seguridad del proyecto, mapear los datos que se devuelven de la base de datos y pasar solo lo que se necesita a la vista podría ser una buena práctica ...

Drozerah
fuente
¡Muchas gracias por tu respuesta! Parece mejor crear un nuevo objeto para evitar la exposición no deseada de datos.
Lee Boon Kong
Gracias por este trabajo
DOMINIQUE GNETO
¿No consume el doble de tiempo para renderizar preparando una nueva lista de una lista preparada?
mustafiz012
6

"Wow, esto funcionó, ¿por qué está sucediendo esto? Actualmente estoy usando express-handlebars (3.1.0) que configuré como motor de renderizado en mi aplicación express". - Lee Boon Kong 12 de enero a las 14:13

"En el pasado, Handlebars le permitía acceder a métodos prototipo y propiedades del objeto de entrada desde la plantilla ... Múltiples problemas de seguridad han surgido de este comportamiento ... En handlebars@^4.6.0. El acceso al prototipo de objeto tiene se ha deshabilitado por completo. Ahora, si usa clases personalizadas como entrada para Manillares, su código ya no funcionará ... Este paquete agrega automáticamente opciones de tiempo de ejecución a cada plantilla de llamadas, deshabilitando las restricciones de seguridad ... Si sus usuarios están escribiendo plantillas y las ejecutas en tu servidor NO debes usar este paquete, sino encontrar otras formas de resolver el problema ...Le sugiero que convierta sus instancias de clase en objetos JavaScript simples antes de pasarlos a la función de plantilla. Cada propiedad o función a la que acceda debe ser una "propiedad propia" de su padre ". - README

Más detalles aquí: https://www.npmjs.com/package/@handlebars/allow-prototype-access

MÉTODO DE SEGURIDAD RÁPIDA Y SUCIA

Uso ( express-handlebarsy mongoose):

express-handlebarsno le permite especificar opciones de tiempo de ejecución para pasar a la función de plantilla. Este paquete puede ayudarlo a deshabilitar las comprobaciones de prototipo para sus modelos.

"Solo haga esto si tiene control total sobre las plantillas que se ejecutan en el servidor".

Pasos:

1 - Instalar dependencia

npm i @handlebars/allow-prototype-access

2 - Use este fragmento como ejemplo para reescribir su servidor express

const express = require('express');
const mongoose = require('mongoose');
const Handlebars = require('handlebars');
const exphbs = require('express-handlebars');

// Import function exported by newly installed node modules.
const { allowInsecurePrototypeAccess } = require('@handlebars/allow-prototype->access');

const PORT = process.env.PORT || 3000;

const app = express();

const routes = require('./routes');

app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static('public'));

// When connecting Handlebars to the Express app...
app.engine('handlebars', exphbs({
    defaultLayout: 'main',
    // ...implement newly added insecure prototype access
    handlebars: allowInsecurePrototypeAccess(Handlebars)
    })
);
app.set('view engine', 'handlebars');

app.use(routes);

const MONGODB_URI = process.env.MONGODB_URI || >'mongodb://localhost/dbName';

mongoose.connect(MONGODB_URI);

app.listen(PORT, function () {
  console.log('Listening on port: ' + PORT);
});

3 - Ejecuta el servidor y baila alegremente.


MÉTODO MÁS SEGURO Y SEGURO

Antes de pasar el objeto devuelto por su llamada AJAX a la plantilla Handlebars, asigne un objeto nuevo con cada propiedad o función a la que necesite acceder en su .hbsarchivo. A continuación puede ver el nuevo objeto hecho antes de pasarlo a la plantilla de Manillares.

const router = require("express").Router();
const db = require("../../models");

router.get("/", function (req, res) {
    db.Article.find({ saved: false })
        .sort({ date: -1 })
        .then(oldArticleObject => {
            const newArticleObject = {
                articles: oldArticleObject.map(data => {
                    return {
                        headline: data.headline,
                        summary: data.summary,
                        url: data.url,
                        date: data.date,
                        saved: data.saved
                    }
                })
            }
            res.render("home", {
                articles: newArticleObject.articles
            })
        })
        .catch(error => res.status(500).send(error));
});

Su consulta de mangosta

Corrígeme si me equivoco, pero creo que esto podría funcionar para tu consulta ...

Confession.find()
    .sort({ date: -1 })
    .then(function (oldDoc) {

        for (var i = 0; i < oldDoc.length; i++) {
            //Check whether sender is anonymous
            if (oldDoc[i].from === "" || oldDoc[i].from == null) {
                oldDoc[i].from = "Anonymous";
            }

            //Add an extra JSON Field for formatted date
            oldDoc[i].formattedDate = formatTime(oldDoc[i].date);
        }

        const newDoc = {
            doc: oldDoc.map(function (data) {
                return {
                    from: data.from,
                    formattedDate: data.formattedDate
                }
            })
        }

        res.render('index', { title: 'Confession Box', success: req.session.success, errors: req.session.errors, confession: newDoc.doc });
        req.session.errors = null;
        req.session.success = null;
    });
Jason Novak
fuente
5

pruebe npm install handlebars versión 4.5.3

npm install [email protected]

Funciono para mi

OOO Gold
fuente
Esto debería ser un comentario
Arun Vinoth
Actualmente estaba usando express-handlebars, versión 3.1.0
Lee Boon Kong
Gracias, he probado tanto el tuyo como el de @ Mason funcionarían, pero no estoy seguro de por qué sucede esto.
Lee Boon Kong
3

A partir de la versión 4.6.0 en adelante, Handlebars prohíbe el acceso a propiedades de prototipo y métodos del objeto de contexto de forma predeterminada. Esto está relacionado con un problema de seguridad descrito aquí: https://mahmoudsec.blogspot.com/2019/04/handlebars-template-injection-and-rce.html

Consulte https://github.com/wycats/handlebars.js/issues/1642

Si está seguro de que solo los desarrolladores tienen acceso a las plantillas, es posible permitir el acceso al prototipo instalando el siguiente paquete:

npm i @handlebars/allow-prototype-access

Si está utilizando el manillar express, debe proceder como:

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

const app = express()

app.engine('handlebars', expressHandlebars({
    handlebars: allowInsecurePrototypeAccess(_handlebars)
}))
app.set('view engine', 'handlebars')
jm4rc05
fuente
Gracias esto funcionó. ¿Entonces tenemos que hacer esto cada vez que tenemos que usar manillares expresos?
Yash Boura
2

Hubo un cambio importante en el reciente lanzamiento de Handlebars que causó este error.

Simplemente puede agregar las configuraciones que sugieren en su documentación, sin embargo, tenga en cuenta que, dependiendo de su implementación, esto podría generar la vulnerabilidad a los ataques XXS y RCE.

https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access

Confession.find()
  .sort({date: -1})
  .then(function(doc){
    for(var i=0; i < doc.length; i++){
      //Check whether sender is anonymous
      if (doc[i].from === "" || doc[i].from == null){
        doc[i].from = "Anonymous";
      }

      //Add an extra JSON Field for formatted date
      doc[i].formattedDate = formatTime(doc[i].date);
    }
    res.render('index', {title: 'Confession Box', success:req.session.success, errors: req.session.errors, confession: doc}, {

      // Options to allow access to the properties and methods which as causing the error.

      allowProtoMethodsByDefault: true,
      allowProtoPropertiesByDefault: true

    });

    req.session.errors = null;
    req.session.success = null;
  });
Roydukkey
fuente
Ahhh, así que ahí es donde agrego las opciones, ¡Muchas gracias!
Lee Boon Kong
1
Esto no funcionó para mí. Se esperaba una devolución de llamada, no un objeto de opciones.
mrg95
0

La creación de otro nuevo objeto o matriz a partir de los datos devueltos por find() resolverá el problema. Vea a continuación una ilustración simple

app.get("/",(req,res)=>{

 let com = require('./MODELCOM')    // loading model
 let source=fs.readFileSync(__dirname+"/views/template.hbs","utf-8");

 com.find((err,data)=>{
    // creation new array  using map
   let wanted = data.map(doc=>{
       return {
           name:doc.name,
           _id:doc._id
        }
   })

    let html= handlebar.compile(source);
  fs.writeFileSync(__dirname+"/views/reciever.html",html({communities:wanted}))
    res.sendFile(__dirname+"/views/reciever.html")
});
DOMINIQUE DE GNETO
fuente