0

I'm learning DOM Scripting with JavaScript and thought it nice to make a simple calculator app, I found the logic easy enough to do but ran into a problem using parseInt to convert the string type arithmetic expression to number type arithmetic expression.

I ended up having to use the eval() function which worked fine for a basic calculator app but on further research I found out the eval() function is a security risk in most casese, I've used a regex expression to cleanse the result but don't know if this is safe enough.

Here is the code snippet I'm unsure is safe to be executed on the client browser.

const equals = document.getElementById("equals");

equals.addEventListener("click", (e) => {
    document.getElementById("result").innerText =  eval(document.getElementById("result").innerText).replace(/[^**-+/*\d]/g, '');                                      
});

NOTE: This code is deployed as a static site on Netlify.

Davidbay
  • 7
  • 2
  • 1
    It's a security risk if you're evaluating code that comes from an external source. If you're generating the code yourself, it's safe. – Barmar Jan 28 '23 at 21:09
  • Nearly 100% of the time, the use of `eval` is unwarranted and another approach is best. Here, you don't need `eval` at all as all you are trying to do is work on a string. Just get the HTML element's value and use `replace` directly on that. – Scott Marcus Jan 28 '23 at 21:21
  • "*I've used a regex expression to cleanse the result but don't know if this is safe enough*" - no, it absolutely is not. You need to cleanse the **input** to `eval`, not the result! (But it's still a bad idea to use it for a calculator app. [Better solutions exist](https://stackoverflow.com/q/5066824/1048572).) – Bergi Jan 28 '23 at 21:38

1 Answers1

0

You should definitely stop using eval().

Executing JavaScript instructions from a string opens up a huge security risk that makes it easy for would-be third-party attackers to inject potentially malicious code into your application without your knowledge or permission.

Another reason not to use eval(), in my view, is that some sources have already marked it as obsolete or deprecated and it is being blocked by default in some environments due to its security risks and slow performance. In other words, support for eval() is at issue and there is a push to possibly phase it out from future versions of Javascript. That means anything you've built that uses it has the potential to eventually stop working.

The good news is eval() has been on its way out for a quite while now so there are plenty of much better, much more secure ways to accomplish just about everything you'd use eval() for. In fact, the code snippet you shared doesn't need eval() at all.

The innerText property you are updating is directly accessible from within the DOM. While we're on the subject, avoid using the innerHTML property. It too poses security risks similar to eval().

This code here should address your concerns:

const equals = document.getElementById("equals");

equals.addEventListener("click", (e) => {
    let result = document.getElementById("result");
    result.innerText = result.innerText.replace(/[^**-+/*\d]/g, '');
    return true;
});

The only place in a calculator app I can think of where a developer might be tempted to use eval() would be to run it's actual calculations. It's sort of a cheat to just feed an entire mathematical expression to eval() rather than construct a proper parser. I suppose it works (for now) but it's a bad practice.

I built a little calculator app you are welcome to study that performs all the key operations one expects a calculator to do without touching eval(). Feel free to check it out: https://calc-work.webflow.io.

Hope you find this helpful. Cheers!

inworlder
  • 17
  • 7
  • "*`eval()` is scheduled to be phased out from future versions of Javascript.*" - no. Where did you get that from? – Bergi Jan 29 '23 at 01:23
  • Please return my reputation points @Bergi: (https://www.geeksforgeeks.org/javascript-eval-function/) (https://docs.oracle.com/cd/E19957-01/816-6408-10/object.htm#1194118) (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Deprecated_and_obsolete_features) (https://udn.realityripple.com/docs/Archive/Web/JavaScript/Object.eval) (https://thehackernews.com/2019/10/firefox-javascript-injection.html) (https://www.sitepoint.com/call-javascript-function-string-without-using-eval/) (https://csplite.com/csp/test153/) – inworlder Jan 29 '23 at 11:07
  • Oh well, how easy it is to spread misinformation… The MDN deprecation list, the MDN page archived on realityripple.com, and the oracle documentation (from 1995!) refer to `Obect.prototype.eval`, not to the [global `eval` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval). The object method is indeed deprecated, obsolete and long long gone - unlike `window.eval`. The sitepoint article you found seems to have fallen for the same misconception in 2013, the geeksforgeeks page is simply wrong, and csplite doesn't actually mention it. – Bergi Jan 29 '23 at 11:26
  • I'm not spreading misinformation. eval() is being phased out everywhere you look. Salesforce blocks it, CSP blocks it, Roku, MondoDb, even Chrome Extensions get rejected for it. I've seen countless dev videos saying it is marked for death. There are many industry discussions telling devs not to use it and/or marking it obsolete and yes even deprecated. I did not make this up @Bergi. The advice I gave the user was sound. You were such a nice person when you helped me with my project. If you disagreed with my post, you could've added you own answer to the user instead of picking a fight with me. – inworlder Jan 29 '23 at 11:37
  • Yes, in general one should not use it when there are better options (and very often there are, especially if you're new to the language), and yes it is being blocked by default in some environments because of its security risks, but it is *not* going to get marked as obsolete or deprecated in the language. There are no such discussion in TC39. – Bergi Jan 29 '23 at 18:29
  • Sorry, I did not mean to accuse you of spreading misinformation, I meant to say that the information you found on the web is wrong or misleading. And yes, the advice you gave is generally sound, but the paragraph "*eval() […] has been officially marked for deprecation on all the major web browsers. [It] is scheduled to be phased out from future versions of Javascript.*" is factually wrong. I'm not trying to pick fights with anyone, I just point out correctness flaws in answers by anyone. – Bergi Jan 29 '23 at 18:33
  • @Bergi I have edited my post in deference to you remarks and insights. I must assert that it would also be inaccurate not to mention that there ARE sources that mark it as deprecated. Just as you assert they are wrong, I assert they are right. And there were many other sources including YouTube videos that I did not cite because the URLs were too long and shortened URLs are not allowed. That said, I have revised my post accordingly. I hope this passes muster and you would do me the courtesy of returning/replacing my reputation points. – inworlder Jan 30 '23 at 07:20
  • Thanks! Could you share some of those sources that make a push to officially deprecate it from the language? – Bergi Jan 30 '23 at 15:35