Manera segura de permitir que los usuarios registren ayudantes de handelbars en nodejs

Tengo una aplicación web de node js que utiliza manillares. Los usuarios me piden que les permita registrar sus propios ayudantes de manillares.

Dudo mucho en dejar que lo hagan … pero lo intentaré si hay una manera segura de hacerlo.

var Handlebars = require("handlebars"); var fs = require("fs"); var content = fs.readFileSync("template.html", "utf8"); //This helper will be posted by the user var userHandlebarsHelpers = "Handlebars.registerHelper('foo', function(value) { return 'Foo' + value; });" //eval(userHandlebarsHelpers); This I do not like! Eval is evil //Compile handlebars with user submitted Helpers var template = Handlebars.compile(content); var handleBarContent = template({ foo: bar }); //Save compiled template and some extra code. 

¡Gracias de antemano!

Debido a que los ayudantes son solo un código Javascript, la única forma en que podría ejecutar de forma segura un Javascript arbitrario del mundo exterior en su servidor es si lo ejecutó en un proceso aislado de la caja de arena o si de alguna forma desinfectó el código antes de ejecutarlo.

Lo primero se puede hacer con máquinas virtuales aisladas y control externo sobre el proceso, pero eso hace que sea muy difícil tener un código auxiliar en algún proceso externo, ya que ahora tiene que desarrollar formas de llamarlas y pasar datos de un lado a otro.

Desinfectar Javascript para estar a salvo de ejecutar exploits en su servidor es una tarea prácticamente imposible cuando su conjunto de API es tan grande como node.js. El navegador tiene un conjunto muy controlado de cosas que Javascript puede hacer para mantener el sistema subyacente a salvo de lo que Javascript puede hacer. node.js no tiene ninguna de esas salvaguardas. Podría poner el código en uno de estos ayudantes para borrar todo el disco duro del servidor o instalar varios virus o casi cualquier explotación malvada que desea codificar. Por lo tanto, ejecutar Javascript arbitrario simplemente no será seguro.

Dependiendo de los problemas exactos que deben resolverse, se puede desarrollar un enfoque basado en datos donde, en lugar de código, el usuario proporciona un conjunto de instrucciones de nivel superior (asigne esto a eso, sustitúyalo por eso, sustitúyalo por eso). mostrar desde este conjunto de datos, etc …) que en realidad no es Javascript, sino más bien algunos metadatos no ejecutables. Es mucho más factible hacerlo seguro porque usted controla todo el código que actúa en estos metadatos, por lo que debe asegurarse de que el código que procesa los metadatos no sea capaz de ser engañado para que haga algo malo.

Siguiendo la entrada de @ jfriend00 y luego de algunas pruebas serias, encontré una manera de hacerlo usando el módulo nodejs vm.

Los usuarios ingresarán a sus ayudantes con este formato:

 [[HBHELPER 'customHelper' value]] value.replace(/[0-9]/g, ""); [[/HBHELPER]] [[HBHELPER 'modulus' index mod result block]] if(parseInt(index) % mod === parseInt(result)) block.fn(this); [[/HBHELPER]] //This will throw an error when executed "Script execution timed out." [[HBHELPER 'infiniteLoop' value]] while(1){} [[/HBHELPER]] 

Traduzco ese bloque en esto y lo ejecuto:

  Handlebars.registerHelper('customHelper', function(value) { //All the code is executed inside the VM return vm.runInNewContext('value.replace(/[0-9]/g, "");', { value: value }, { timeout: 1000 }); }); Handlebars.registerHelper('modulus', function(index, mod, result, block) { return vm.runInNewContext('if(parseInt(index) % mod === parseInt(result)) block.fn(this);', { index: index, mod: mod, result: result, block: block }, { timeout: 1000 }); }); Handlebars.registerHelper('infiniteLoop', function(value) { //Error return vm.runInNewContext('while(1){}', { value: value }, { timeout: 1000 }); }); 

Hice varias pruebas hasta el momento, intentando eliminar archivos, requerir módulos, bucles infinitos. Todo va perfectamente, todas esas operaciones fallaron.

Ejecutar la función de callback del ayudante del manillar en una máquina virtual fue lo que hizo que esto funcionara para mí, porque mi principal problema al usar las máquinas virtuales y ejecutar todo el código interno era agregar esos ayudantes a mi objeto global de manillares.

Lo actualizaré si encuentro una forma de explotarlo.

    Intereting Posts