Javascript中算术expression式的安全评估
我需要在Javascript中评估用户input的算术expression式,比如“2 *(3 + 4)”,但是我不想为了安全的原因而使用eval
。
我可以删除所有不是数字或操作符的字符,但是我不确定这是否安全,如果用户可以使用cos
, sqrt
等函数,那将会很好。
有没有任何Javascript库进行算术expression式评估?
你可以尝试JavaScript Expression Evaluator :
这个库是Raphael Graf的ActionScript Expression Parser的修改版本。 当我编写JavaScript函数绘图器时,我想要使用JavaScript的eval函数更好的select 。 目前没有安全风险,因为您只能在自己的浏览器中运行代码,但对于math(Math.pow(2 ^ x)而不是2 ^ x等)来说并不方便。
那么你的代码将会是这样的:
console.info ( Parser.evaluate( "2 * (3 + 4)" ) ); //prints 14
正如已经提到的,任何用户可以做的最大的损害就是他们已经可以在任何主stream浏览器中使用内置控制台。 但是,如果你想限制用户使用Math
属性/方法,你可以写一个简单的正则expression式来为你处理。 像这样的东西应该工作:
function mathEval (exp) { var reg = /(?:[az$_][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
出于安全的原因,但正则expression式应该使它非常安全,因为它排除任何不是Math
对象的直接属性和大多数非mathJS运算符的单词,包括赋值运算符( =
)和二元运算符。 更难的方法是编写一个标记器来parsingmathexpression式,因为它不是一种常规的语言。
随意尝试打破我写的工作示例 ,如果可以的话,或者如果您发现问题,留下评论,我会看看我能做些什么来解决它。
注意:Yi Jiang 在JavaScript聊天中提到,允许像Math.PI
这样的小写字母也是有用的。 如果是这样的话,你可以在replace函数中添加else if
语句:
else if (Math.hasOwnProperty($0.toUpperCase()) return "Math."+$0.toUpperCase();
在if
和else
语句之间添加它( 例子 )。
您可以使用math.js中的高级expression式parsing器,它不使用JavaScript的eval。
用法:
var ans = math.eval('2 * (3 + 4)');
或者使用parsing器(它支持variables和函数赋值):
var parser = math.parser(); var ans = parser.eval('2 * (3 + 4)');
您可以使用正则expression式来replace除白名单之外的所有内容。 但是由于JavaScript是在客户端上执行的(除非你运行的是AOL http服务器),任何可以修改input的人都可以修改代码 – 所以你并没有真正使它比现在更安全。
尝试nerdamer
var result = nerdamer('sqrt(4)+cos(1)-2').evaluate(); document.getElementById('text').innerHTML = result.text();
<script src="js/nerdamer.core.js"></script> <div id="text"></div>