Javascript 中算术表达式的安全评估

IT技术 javascript parsing math
2021-01-26 21:04:51

我需要在 Javascript 中评估用户输入的算术表达式,如“2 * (3 + 4)”,但eval出于安全原因我不想使用

我可以去掉所有的不是数字或运营商的角色,但我不知道这将是安全的反正这将是很好,如果用户可以使用类似的功能cossqrt等...

是否有任何 Javascript 库可以进行算术表达式评估?

5个回答

你可以试试JavaScript 表达式评估器

该库是 Raphael Graf 的 ActionScript Expression Parser 的修改版本。当我编写 JavaScript 函数绘图仪时,我想要一个更好的替代方法来使用 JavaScript 的 eval 函数目前没有安全风险,因为你只能在自己的浏览器中运行代码,但它对数学不太方便(Math.pow(2^x) 而不是 2^x 等)。

那么你的代码将是这样的:

console.info ( Parser.evaluate( "2 * (3 + 4)" ) ); //prints 14
谢谢!这正是我一直在寻找的,我发誓我在谷歌上搜索了所有我能想到的“表达评估”的可能变化......
2021-04-06 21:04:51

如前所述,任何用户可能造成的最大损害几乎是他们在任何主要浏览器中使用内置控制台已经可以做到的。但是,如果您想限制用户使用Math属性/方法,您可以编写一个简单的正则表达式来为您处理。这样的事情应该工作:

function mathEval (exp) {
    var reg = /(?:[a-z$_][a-z0-9$_]*)|(?:[;={}\[\]"'!&<>^\\?:])/ig,
        valid = true;
       
    // Detect valid JS identifier names and replace them
    exp = exp.replace(reg, function ($0) {
        // If the name is a direct member of Math, allow
        if (Math.hasOwnProperty($0))
            return "Math."+$0;
        // Otherwise the expression is invalid
        else
            valid = false;
    });
    
    // Don't eval if our replace function flagged as invalid
    if (!valid)
        alert("Invalid arithmetic expression");
    else
        try { alert(eval(exp)); } catch (e) { alert("Invalid arithmetic expression"); };
}

我意识到eval出于安全原因您不想使用,但是正则表达式应该使它非常安全,因为它排除了任何不是对象的直接属性的单词Math和大多数非数学 JS 运算符,包括赋值运算符 ( =)和二元运算符。更难的方法是编写一个分词器来解析数学表达式,因为它不是常规语言。

随意尝试打破我写工作示例,如果可以或如果您发现问题,请发表评论,我会看看我能做些什么来解决它。


注意:Yi Jiang [在 JavaScript 聊天中](https://chat.stackoverflow.com/rooms/17/javascript) 提到允许小写字母“Math.PI”之类的东西也可能有用。如果是这种情况,您可以在替换函数中添加以下 `else if` 语句:
else if (Math.hasOwnProperty($0.toUpperCase())
    return "Math."+$0.toUpperCase();

ifandelse语句之间添加它示例)。

用例可以包括在服务器端评估用户输入。那么安全就很重要了。
2021-03-16 21:04:51
“任何用户可能造成的最大损害几乎就是他们在任何主要浏览器中使用内置控制台已经可以做的事情”是基于错误前提。字符串通过服务器和 URL 来自浏览器外部。最好的策略是编写代码时假设您的函数的输入来自您不希望其他开发人员添加到您的应用程序的地方,这意味着不要使用过于强大的运算符,例如eval.
2021-03-18 21:04:51
@AndyE,我对“评估用户输入”这句话的理解包括在用户 Alice 的浏览器中评估来自用户 Carol 的输入。在每个 PM 和他们的母亲都试图让他们的网站“社交”之前,更有限的阅读是合理的,但今天我认为更广泛的阅读应该是默认的,除非应用程序规范另有说明。
2021-03-24 21:04:51
@Mike:我很难 100% 同意。虽然您在评估来自其他来源的输入时所说的是正确的,但当您仅评估用户输入时,我坚持我的答案。
2021-04-09 21:04:51

您可以使用 math.js 中的高级表达式解析器,它不使用 JavaScript 的 eval。

http://mathjs.org

用法:

var ans = math.evaluate('2 * (3 + 4)');

或使用解析器(支持变量和函数赋值):

var parser = math.parser();
var ans = parser.evaluate('2 * (3 + 4)');

您可以使用正则表达式替换除白名单之外的所有内容。但由于JavaScript是在客户端上执行的(除非你正在运行的AOL http服务器)人谁可以修改输入可以修改代码,以及-所以你没有真正使其成为任何或多或少的安全比它已经是.

这取决于键入要计算的表达式的用户与计算此表达式的用户是否相同。
2021-03-25 21:04:51

试试书呆子

var result = nerdamer('sqrt(4)+cos(1)-2').evaluate();
document.getElementById('text').innerHTML = result.text();
<script src="http://nerdamer.com/js/nerdamer.core.js"></script>
<div id="text"></div>