简体   繁体   中英

Securing user defined javascript function to protect node.js server

I'm making a math-teaching webpage (NodeJS backend and Angular frontend). I want a special kind of users (creator) to create mathematical exercises. One of these exercises can look like this:

Marie has ${nums[0]} oranges and ${nums[1]} apples. How many fruits does she have?

Now I want the creator to write a number generating function like this:

const generate = () => {
  const nums = new Array(2).fill(0).map(e => Math.floor(Math.random() * 10)
  return { nums: nums, answer: nums.reduce((p, c) => p + c, 0) }
}

This function should be send to the server and stored. When the user want to try the test, the question should be executed on the server. What should I do to protect the server from malicious code like:

const generate = () => {
  process.exit()
}

Really short answer, this is never really safe for the server. It is impossible to prove that a program is safe. There are mitigations such as sandboxing that help, but it is ultimately always a risk. For this application, possibly an unnecessary one.

Consider some way of communicating the formula that does not require exec. One way might be to send an abstract syntax tree of some sort, or to parse the mathematical expression.

This npm package seems promising. Fill a math expression string template the same way you fill the written question template. It might be necessary to provide another object to define what random numbers are needed and map them to names for use in the templates. math-expression-evaluator

This will not be safe for the server/client.

Not sure this is the correct way or not. but you can restrict global variables access

 const generate1 = () => { process.exit(); } const generate2 = () => { const nums = new Array(2).fill(0).map(e => Math.floor(Math.random() * 10)); return { nums: nums, answer: nums.reduce((p, c) => p + c, 0) } } const funcStr1 = generate1.toString(); const funcStr2 = generate2.toString(); //get all global variables key from 'global' and check it exist or not // const globals = Object.keys(global); // will return same result as below remove keys which you want to allow const globals = ['DTRACE_NET_SERVER_CONNECTION', 'DTRACE_NET_STREAM_END', 'DTRACE_HTTP_SERVER_REQUEST', 'DTRACE_HTTP_SERVER_RESPONSE', 'DTRACE_HTTP_CLIENT_REQUEST', 'DTRACE_HTTP_CLIENT_RESPONSE', 'COUNTER_NET_SERVER_CONNECTION', 'COUNTER_NET_SERVER_CONNECTION_CLOSE', 'COUNTER_HTTP_SERVER_REQUEST', 'COUNTER_HTTP_SERVER_RESPONSE', 'COUNTER_HTTP_CLIENT_REQUEST', 'COUNTER_HTTP_CLIENT_RESPONSE', 'global', 'process', 'Buffer', 'clearImmediate', 'setImmediate', // 'clearInterval', // 'clearTimeout', // 'setInterval', // 'setTimeout' ]; const hasGlobal1 = globals.some((g) => funcStr1.includes(`${g}.`)); const hasGlobal2 = globals.some((g) => funcStr2.includes(`${g}.`)); console.log('generate1 has global', hasGlobal1); console.log('generate2 has global', hasGlobal2); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM