2011-02-21 17 views
13

Potrzebuję do oceny wprowadzonych przez użytkownika wyrażeń arytmetycznych, takich jak "2 * (3 + 4)" w JavaScript, ale nie chcę używać eval ze względów bezpieczeństwa.Bezpieczna ocena wyrażeń arytmetycznych w JavaScript

mogłem rozebrać wszystkie znaki, które nie są liczbami lub operatorów, ale nie jestem pewien, że to będzie bezpieczne i tak byłoby miło, gdyby użytkownik może korzystać z funkcji takich jak cos, sqrt, itp ...

Czy są jakieś biblioteki JavaScript, które wykonują obliczenia arytmetyczne?

+0

Jeśli nie przeturlasz się samodzielnie, nie rozwiążesz żadnych problemów z bezpieczeństwem? – James

Odpowiedz

20

można spróbować JavaScript Expression Evaluator:

Biblioteka ta jest zmodyfikowaną wersją Raphael Grafa ActionScript Expression Parser. Kiedy napisałem skrypt funkcyjny JavaScript , chciałem, aby było lepsze, niż używanie funkcji eval JavaScript eval. Obecnie nie ma zagrożenia bezpieczeństwa , ponieważ można uruchomić tylko kod we własnej przeglądarce, ale nie jest to wygodne dla matematyki (Math.pow (2^x) zamiast 2^x itd.).

następnie Twój kod będzie tak:

console.info (Parser.evaluate("2 * (3 + 4)")); //prints 14 
+1

Dzięki! Właśnie tego szukałem i przysięgam, że szukałem w Google informacji o wszystkich możliwych odmianach "oceny ekspresji", które mogłem wymyślić ... –

1

Można użyć wyrażenia regularnego, aby zastąpić wszystko poza białą listą. Ale ponieważ javascript jest wykonywany na kliencie (chyba, że ​​korzystasz z serwera http AOL), każdy, kto może modyfikować dane wejściowe, może także zmodyfikować kod - tak więc nie czynisz tego ani bardziej, ani mniej bezpiecznym niż on. już jest.

+1

To zależy od tego, czy użytkownik wpisujący wyrażenia, które ma zostać ocenione, jest taki sam, jak użytkownik oceniający to wyrażenie. – Bruno

9

Jak już wspomniano, najbardziej uszkodzić każdy użytkownik może zrobić jest dość dużo, co mogliby już nie za pomocą wbudowanego w konsolę którymś z główne przeglądarki. Jeśli jednak chcesz ograniczyć użytkownika do korzystania z właściwości/metod Math, możesz napisać proste wyrażenie regularne, aby obsłużyć to za Ciebie. Coś jak to powinno działać:

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"); }; 
} 

Zdaję sobie sprawę, że nie chcesz używać eval ze względów bezpieczeństwa, ale regex powinien zrobić to całkiem bezpieczne, gdyż wyklucza jakiekolwiek słowa, które nie są bezpośrednie właściwości obiekt Math i większość nie-matematycznych operatorów JS, w tym operator przypisania (=) i operatory binarne. Trudniejszą metodą byłoby napisanie tokenizera, aby przeanalizować wyrażenie matematyczne, ponieważ nie jest to zwykły język.

Możesz spróbować złamać working example, napisałem, jeśli możesz, lub jeśli zauważysz problem, zostaw komentarz, a zobaczę, co mogę zrobić, aby to naprawić.


Uwaga: Yi Jiang wspomniano in JavaScript chat, że może to być również przydatne w celu umożliwienia małych liter dla rzeczy jak Math.PI. Jeśli to przypadek, można po prostu dodać następujące else if oświadczenie w funkcji zastępczej:

else if (Math.hasOwnProperty($0.toUpperCase()) 
    return "Math."+$0.toUpperCase(); 

Dodaj go między rachunku if i else (example).

+0

Świetne podejście, pomogło mi rozwiązać podobny problem. – odiseo

+3

"Najwięcej obrażeń, które mógłby zrobić każdy użytkownik zrób to, co już mogli zrobić za pomocą wbudowanej konsoli w którejkolwiek z głównych przeglądarek "opiera się na fałszywych przesłankach. Ciągi pochodzą spoza przeglądarki za pośrednictwem serwerów i adresów URL. Najlepszą zasadą jest kodowanie przy założeniu, że dane wejściowe do twojej funkcji będą pochodzić z miejsc, których się nie spodziewasz, tak jak inni deweloperzy dodają do twojej aplikacji, co oznacza, że ​​nie używasz zbyt potężnych operatorów takich jak 'eval'. –

+1

@Mike: Ciężko mi zgodzić się na 100%. Chociaż to, co powiedziałeś, jest prawdziwe podczas oceny danych wejściowych z innych źródeł, pozostaje mi moja odpowiedź, gdy oceniasz tylko dane wprowadzone przez użytkownika. –

3

Możesz użyć zaawansowanego parsera wyrażeń z math.js, który nie wykorzystuje eval JavaScript.

http://mathjs.org

Zastosowanie:

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

lub użyć parser (który obsługuje zmienne i przypisania) funkcji:

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

Spróbuj nerdamer

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>

Powiązane problemy