String zu Java Anweisung getString("*** java code ***")

AlexVo

Mitglied
Guten Morgen,

ich bin neu hier und hoffe das ihr mir bei meinem Problem helfen könnt.

Ich suche eine Möglichkeit Java Code, der als String übergeben wird, auszuführen.

Beispiel: Ich habe eine String (test2) dem ein Wert zugewiesen werden soll. Dafür gibt es ein getString Methode die als Übergabe-Wert Java Code zur Ermittlung des Strings hat. Der Java Code ist variable.

[CODE lang="java" title="Beispiel" highlight="3,5-8"]//Code im Programm
String test = (new Date()) + ("test".equals("test") ? " test_1" : " test_2") + " blabal";
String test2 = getString("(new Date()) + (\"test\".equals(\"test\") ? \" test_1\" : \" test_2\") + \" blabal\"");
...
private String getString(String code) {
//ToDo Ausführung code und return Result
return "???";
}
[/CODE]

test und test2 sollte das selbe Ergebnis dann haben (ja Date könnte natürlich ein Sekunde unterschiedlich sein).

Vielen Dank für die Hilfe!

Alex
 
Es geht um ein sehr umfassende Anwendung, wo der User eigene Werte erstellen soll und Importwerte bekommt. Der User kann ("soll können") Werte selber manipulieren und eigene kleine Convertierungen durchführen (Replace/ If Then Else usw.). Er wird diesen Convertierungscode im FrontEnd eingeben.

Ich hoffe das Hilft beim Verständnis.
 
Ich sehe da im Augenblick auch keinen wirklichen Sinn, aber JSR 223 bietet sowas. Java Scripting API:



Aber das sehe ich bei dem Anwendungsfall nicht wirklich als sinnvoll an.

Aber das wäre die technische Möglichkeit.
 
Ansonsten gibt es auch die Compiler API: https://docs.oracle.com/javase/8/docs/api/javax/tools/JavaCompiler.html

ABER Mit der Compiler-API auf jeden Fall, aber vermutlich auch mit Scripting API holst du dir riesige Sicherheitslücken rein. Es ist in 99,9% der Fälle eine schlechte Idee User auf einem eigenen System Code ausführen zu lassen. Nicht umsonst ist eval z:B. in PHP eine der Methoden, die für viele Sicherheitslücken verantwortlich ist.
 
Hallo,

vielen Dank. Habe das mal getestet.

[CODE lang="java" title="Example"]private String getString(String code) throws ScriptException, NoSuchMethodException {

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");

Bindings obj = (Bindings) engine.eval("var obj = { value: " + code + " }; obj; ");
String value = (String) obj.get("value");
return value;

}[/CODE]

Das tut.

Sicherheit ist eine Wichtige Frage, Gibt es Möglichkeiten den Code zu schützem, das nur zum Beispiel String und Date Funktionen ausgeführt werden? Und es soll ja nur eine Befehlszeile (also eine zuweisung) sein.
 
Du kannst Zur Not eine eigene Script Engine schreiben, die nur das erlaubt, das Du erlauben willst ...

Aber wenn es um Importe und so geht, da kann man durchaus diverse Dinge akzeptieren. Ich würde diese aber separat von der eigentlichen Datenbank / Applikation halten.

Ich kenne die genauen Anforderungen nicht, aber man könnte einen Support ja auch durchaus etwas aufteilen und dann über eine separate Datenbank laufen lassen. Dann hätte man ein gewisses Tooling, das hilft, Tabellen in dieser Datenbank zu befüllen (z.B. über Importmechanismen, die Du bereit stellst).

Und dann hat der Anwender direkt eine SQL Eingabemöglichkeit, d.h. er kann Connection String und die Abfrage vorgeben. Da die Datenbank komplett in "Anwenderkontrolle" ist, ist da erst einmal keine Sicherheitslücke. Er kann da zwar alles mögliche machen, aber wenn schon...
Und das gibt dem Kunden auch die Möglichkeit, wirklich frei Daten anzupassen. Ggf. kritische Daten kann er heraus filtern / löschen, ehe Du die Daten bekommst.

Aber da ist wirklich immer die Frage, was die genauen Anforderungen sind. Was muss erreicht werden?
 
Ich würde dem User nur "Bausteine" geben, mit denen er seine Modifikationen und Konvertierungen "zusammensetzen" kann.

Dann kannst du im das im Backend ohne das ganze Scripting lösen, v.a. wenn Security wichtig ist, würde ich einen solchen Weg auf jeden Fall bevorzugen.
 
Ja wir haben angefangen einen eigenen Stringparser zu schreiben für IF Then Else, aber es ist sehr aufwendig und dadurch das man Java Code schreiben könnte, kann man auf die String Funktionen und IF Then Else sehr leicht zugreifen. Ich überlege ein Parser zu schreiben der die ";" z.B. checkt damit er keinen mehrzeiligen Code eingeben kann. Ausserdem habe ich gesehen, dass wenn man keine classes importiert und loads macht nur sehr beschränkte Klassen und Methoden zur Verfügung hat
 
Ich spiele jetzt mal den Buhmann - das mache ich auch gerne im Projekt 🙂

Brauchst du das? Wird das überhaupt jemand nutzen? Ist es den Aufwand wert? Die Frage kannst nur du beantworten und musst du auch nicht hier beantworten.
Aber dieses Feature hört sich nach einem klassischen Feature an, was irgendjemand für eine gute Idee hält, weil es total flexibel ist und viel ermöglicht - nur leider übersteigt die Komplexität der Nutzung die Fähigkeiten von 99% der Anwender. Sprich, stelle sicher, dass dieses Feature wirklich gebraucht wird und die Anwender auch in der Lage sind es zu nutzen. Oder ob nicht eine deutlich abgespeckte, Klicki-Bunti Version reicht wo ich vielleicht aus 20 Standard-Konvertierungen wählen kann. Damit deckt man dann vielleicht nur 80% der denkbaren Anwendungsfälle ab - aber für die wird es dann wenigstens genutzt.

Ich erlebe es oft genug (und ich bin da auch nicht gefeit vor - im Gegenteil) das man sich tolle Lösungen für Probleme überlegt und am Ende ist das ganze viel zu komplex und eigentlich wird was einfacheres benötigt.
 
Was mir gerade noch in den Sinn kommt, was du dir anschauen kannst, wäre Blockly: https://developers.google.com/blockly

Das wird in Smart Home Systemen gerne verwendet. Damit kann man ich über so Block-Strukturen Programm-Code zusammenstellen (Schleifen, Bedingungen, Verarbeitungen etc.). Das ist - im Gegensatz zu der Anwender muss syntaktisch korrekten Code schreiben - deutlich Benutzerfreundlicher. Und da müsstest dann "nur" die Custom Blöcke definieren, die für deine Anwender hilfreich sind.
 
Verstehe ich den Einwand, aber ich denke, dass meine Nutzer (PowerUser) die Java Funktionalität nutzen können. Es ist eben hier meiner Meinung nach gerade umgekehrt, wir müssten so viele eventualitäten programmieren, um die Funktionalität auf 80 % zu bringen, die mir die Java Funktionalität von Hause aus bringt. Wir müssen nur dafür sorgen, dass er keinen Unsinn macht.

Hier mal der erste Protoype vom Command Check. Es wird geschaut, ob ausserhalb von Zeichenfolgen ein ";" vorkommt, dann wird das Kommando abgelehnt.

[CODE lang="java" title="Example"]private String checkCommand(String text) {
String REGEX_STRINGS = "(\"([^\"]|\"\")*\")";

String workText = text.replace("\\\"", "$$$");

Matcher m = Pattern.compile(REGEX_STRINGS).matcher(workText);
StringBuffer sb = new StringBuffer();

// ESCAPE Strings
int i = 0;
while (m.find()) {
m.appendReplacement(sb,
Matcher.quoteReplacement("\"$" + i + "$\""));
i++;
}
m.appendTail(sb);
String testString = sb.toString();
System.out.println(testString);
if (testString.contains(";")) {
throw new IllegalArgumentException("command string not allowed");
}
return text;
}[/CODE]
 
Es kann ja durchaus sein, dass es bei dir sinnvoll ist - das kann und will ich nicht beurteilen.

Aber die Absicherung ist haarig. Weil das was du machst, funktioniert nicht vollständig. Folgender Code ist valider Java-Code:

Java:
        System.out.println("Test")\u003B

Import Statements sind in Java komplett optional, ich kann immer mit dem Full Qualified Class Name auf Klassen zugreifen.
 
Wenn ich das richtig getetstet habe, findet
Java:
if (testString.contains(";")) {
            throw new IllegalArgumentException("command string not allowed");
        }
auch das unicode zeichen vom simikolon.
 
im String steht nicht das Unicode Zeichen, sondern die Unicode-Repräsentation 🙂

Beispiel:

Test2.txt
Java:
package de.limdul.javaforum\u003B

public class Test2 {

    public Test2() {
        System.out.println("Ich bin Evil")\u003B
    }
}

Test.java:
Java:
package de.limdul.javaforum;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Test {

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(
                "C:\\Pfad\\zur\\Test2.txt"));
        String line = null;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
            System.out.println(line.contains(";"));
        }
    }

}

Ausgabe:
package de.limdul.javaforum\u003B
false

false
public class Test2 {
false

false
public Test2() {
false
System.out.println("Ich bin Evil")\u003B
false
}
false
}
false

Derartige Fallstricke wird es viele geben. Du müsstest mal schauen (da hab ich aber keine Ahnung davon) wie man solchen Code in einer Sandbox mit limitierten Rechten ausführen kann - weil das wäre dann die zweite Schutz-Schicht. Wenn jemand es schafft durch die Prüfungen ob der Code "gut aussieht" zu kommen, kommt er damit dann im Idealfall nicht an sensitive Informationen ran.
 
Der Test passt sowohl mit ; als auch mit dem unicode

Java:
 @Test
    public void semicolonTest() {
        String test = "abc;def";
        Assert.assertTrue(test.contains(";"));
        Assert.assertTrue(test.contains("\u003B"));

        String test2 = "abc\u003Bdef";
        Assert.assertTrue(test2.contains(";"));
        Assert.assertTrue(test2.contains("\u003B"));
    }

alle Test sind ok
 
Der Test passt sowohl mit ; als auch mit dem unicode

Java:
 @Test
    public void semicolonTest() {
        String test = "abc;def";
        Assert.assertTrue(test.contains(";"));
        Assert.assertTrue(test.contains("\u003B"));

        String test2 = "abc\u003Bdef";
        Assert.assertTrue(test2.contains(";"));
        Assert.assertTrue(test2.contains("\u003B"));
    }

alle Test sind ok
Dein String ist falsch. Der String test2 muss ein
Code:
        String test2 = "abc\\u003Bdef";
Du musst das Zeichen dort escapen, ansonsten steht da wirklich das ; drin. Es steht eben nicht das Semikolon drin sondern die Repräsentation davon.
 

Zurück
Oben