mirror of
https://github.com/josdejong/mathjs.git
synced 2025-12-08 19:46:04 +00:00
* fix: disable parser functions in the CLI (security issue) * fix: ensure `ObjectWrappingMap` doesn't allow deleting unsafe properties (security issue) * fix: enable using methods and (safe) properties on plain arrays * docs: update the "Less vulnerable expression parser" section in the docs * chore: fix typos and linting issues * chore: keep functions like `simplify` enabled in the CLI * docs: update the security page * fix: ensure `ObjectWrappingMap.keys` cannot list unsafe properties * fix: when overwriting a rawArgs function with a non-rawArgs function it was still called with raw arguments * docs: fix a typo
96 lines
4.4 KiB
Markdown
96 lines
4.4 KiB
Markdown
# Security
|
|
|
|
Executing arbitrary expressions like enabled by the expression parser of
|
|
mathjs involves a risk in general. When you're using mathjs to let users
|
|
execute arbitrary expressions, it's good to take a moment to think about
|
|
possible security and stability implications, especially when running
|
|
the code server side.
|
|
|
|
## Security risks
|
|
|
|
A user could try to inject malicious JavaScript code via the expression
|
|
parser. The expression parser of mathjs offers a sandboxed environment
|
|
to execute expressions which should make this impossible. It's possible
|
|
though that there are unknown security vulnerabilities, so it's important
|
|
to be careful, especially when allowing server side execution of
|
|
arbitrary expressions.
|
|
|
|
The expression parser of mathjs parses the input in a controlled
|
|
way into an expression tree or abstract syntax tree (AST).
|
|
In a "compile" step, it does as much as possible preprocessing on the
|
|
static parts of the expression, and creates a fast performing function
|
|
which can be used to evaluate the expression repeatedly using a
|
|
dynamically passed scope.
|
|
|
|
The parser actively prevents access to JavaScripts internal `eval` and
|
|
`new Function` which are the main cause of security attacks. Mathjs
|
|
versions 4 and newer does not use JavaScript's `eval` under the hood.
|
|
Version 3 and older did use `eval` for the compile step. This is not
|
|
directly a security issue but results in a larger possible attack surface.
|
|
|
|
When running a node.js server, it's good to be aware of the different
|
|
types of security risks. The risk when running inside a browser may be
|
|
limited, though it's good to be aware of [Cross side scripting (XSS)](https://www.wikiwand.com/en/Cross-site_scripting) vulnerabilities. A nice overview of
|
|
the security risks of node.js servers is listed in the article [Node.js security checklist](https://blog.risingstack.com/node-js-security-checklist/) by Gergely Nemeth.
|
|
|
|
### Less vulnerable expression parser
|
|
|
|
There is a small number of functions which yield the biggest security
|
|
risk in the expression parser:
|
|
|
|
- `import` and `createUnit` which alter the built-in functionality and
|
|
allow overriding existing functions and units, and `reviver` which parses
|
|
values into class instances.
|
|
- `evaluate`, `parse`, `simplify`, `derivative`, and `resolve` which parse
|
|
arbitrary input into a manipulable expression tree.
|
|
|
|
To make the expression parser less vulnerable whilst still supporting
|
|
most functionality, these functions can be disabled:
|
|
|
|
```js
|
|
import { create, all } from 'mathjs'
|
|
|
|
const math = create(all)
|
|
const limitedEvaluate = math.evaluate
|
|
|
|
math.import({
|
|
// most important (hardly any functional impact)
|
|
'import': function () { throw new Error('Function import is disabled') },
|
|
'createUnit': function () { throw new Error('Function createUnit is disabled') },
|
|
'reviver': function () { throw new Error('Function reviver is disabled') },
|
|
|
|
// extra (has functional impact)
|
|
'evaluate': function () { throw new Error('Function evaluate is disabled') },
|
|
'parse': function () { throw new Error('Function parse is disabled') },
|
|
'simplify': function () { throw new Error('Function simplify is disabled') },
|
|
'derivative': function () { throw new Error('Function derivative is disabled') },
|
|
'resolve': function () { throw new Error('Function resolve is disabled') },
|
|
}, { override: true })
|
|
|
|
console.log(limitedEvaluate('sqrt(16)')) // Ok, 4
|
|
console.log(limitedEvaluate('parse("2+3")')) // Error: Function parse is disabled
|
|
```
|
|
|
|
|
|
### Found a security vulnerability? Please report in private!
|
|
|
|
You found a security vulnerability? Awesome! We hope you don't have bad
|
|
intentions and want to help fix the issue. Please report the
|
|
vulnerability in a private way by contacting one of the maintainers
|
|
via mail or another private channel. That way we can work together
|
|
on a fix before sharing the issue with everybody including the bad guys.
|
|
|
|
## Stability risks
|
|
|
|
A user could accidentally or on purpose execute a
|
|
heavy expression like creating a huge matrix. That can let the
|
|
JavaScript engine run out of memory or freeze it when the CPU goes
|
|
to 100% for a long time.
|
|
|
|
To protect against this sort of issue, one can run the expression parser
|
|
in a separate Web Worker or child_process, so it can't affect the
|
|
main process. The workers can be killed when it runs for too
|
|
long or consumes too much memory. A useful library in this regard
|
|
is [workerpool](https://github.com/josdejong/workerpool), which makes
|
|
it easy to manage a pool of workers in both browser and node.js.
|