将 eval 用于客户端 JavaScript 计算器是否安全?

Is it safe to use eval for a client-side JavaScript calculator?

提问人:garydavenport73 提问时间:7/1/2022 最后编辑:Peter Mortensengarydavenport73 更新时间:12/16/2022 访问量:726

问:

我正在制作一个计算器,它作为用户浏览器的静态 HTML 页面。该页面不用于将任何信息提交回服务器。除了这个计算器之外,网页上不会出现任何其他内容。

在这种情况下使用“eval”是否安全?或者换一种说法,在这种情况下使用 eval 会不会造成额外的安全风险?

在我看来,用户似乎不能通过简单地打开浏览器开发工具来对这个页面做任何他们无法做到的事情。我一直读到“从不”使用 eval,但在这种情况下,这似乎很有意义。

下面是一个示例计算器:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Calculator</title>
</head>

<body>
    <input id="input" type="text">
    <button onclick="{
        let result= '';
        try {
            result = eval(document.getElementById('input').value);
        } catch (error) {
            result = error;
        }
        console.log(result);
        document.getElementById('result').innerHTML=result;
        }">calculate</button>
    <div id="result">result here</div>
</body>

</html>

JavaScript 安全 评估客户端

评论

0赞 Míng 8/26/2022
我还以这种方式用 JavaScript 制作了一个计算器。ScriptCalculator:iwill.im/url/2,GitHub:github.com/iwill/ScriptCalculator

答:

1赞 CertainPerformance 7/1/2022 #1

它可能会打开页面以执行任意代码。考虑一下是否有人设法说服您的一个或几个用户:“尝试将其粘贴到输入字段中。你不会相信接下来会发生什么!如果您在客户端上保存任何与用户相关的数据,例如 cookie 中的登录凭据,或本地存储或 IndexedDB 中的数据等,这是一个很大的潜在问题。

即使您不存储任何此类数据,对输入值进行清理也可能是一个好主意,以便它只包含数学表达式,而不包含其他任何内容。例如,只允许你想要的数字和运算符是微不足道的,也许.这很容易做到,而且很安全,所以你应该这样做。+-*/

另外,不要将函数放入内联处理程序中(或根本不使用内联处理程序)——这是非常糟糕的做法。使用 正确附加事件侦听器。addEventListener

document.querySelector('button').addEventListener('click', () => {
  const sanitizedValue = document.getElementById('input').value
    .replace(/[^-+/*\d]/g, '');
  try {
    document.getElementById('result').textContent = eval(sanitizedValue);
  } catch(e) {
    document.getElementById('result').textContent = 'Syntax not correct';
  }
});
<input id="input" type="text">
<button>calculate</button>
<div id="result">result here</div>

.replace(/[^-+/*\d]/g, '');做:

  • 匹配任何不符合以下条件的字符:
    • -, , ,+/*
    • 或(任何数字)\d
  • 将所有此类匹配的字符替换为空字符串

评论

0赞 garydavenport73 7/1/2022
谢谢你的回答。这是一个很好的建议。我没有考虑过客户端存储和 cookie 方面。关于“如果您在客户端上保存任何与用户相关的数据,这是一个很大的潜在问题”。在这样的输入中使用 eval(expression) 是否会比打开浏览器开发人员工具并在控制台中使用 eval(expression) 带来任何额外的风险?
0赞 CertainPerformance 7/1/2022
不,它没有。 网页内部的脚本相对安全,因为它只能访问网站的数据。但控制台具有更多权限,并且可以访问顶部窗口,而没有任何 CORS 限制。如果攻击者可以让受害者将一些代码粘贴到他们的控制台中,那么无论粘贴的代码是否包含,受害者都可能丢失(并不是说如果攻击者具有该级别的访问权限,就没有任何理由)evalevaleval
0赞 Míng 8/26/2022 #2

永远不要使用 eval()

来自 MDN,它还说:

幸运的是,有一个非常好的替代方法:使用构造函数。eval()Function

所以,你可以这样替换:eval()

let result= '';
try {
    result = Function(`"use strict";return (${document.getElementById('input').value})`)();
}
catch (error) {
    result = error;
}

它与 几乎相同,只是:eval

在不带 的函数中,对象在全局作用域中被计算,因此它是安全的eval()

评论

0赞 CertainPerformance 1/2/2023
使用函数构造函数在安全性方面与 没有太大区别。它们都允许任意代码执行。无论任意代码是否在全局范围内运行,潜在的攻击者仍然能够抓取您在该域上拥有的所有用户数据,并且许多人会做其他令人讨厌的事情。无论使用还是函数构造函数,如果代码是恶意的,无论如何您都会遇到深深的麻烦。evaleval