Execute script in Java program at runtime - java

I encounter this issue when calculating the price for a product but the formula changes nearly every day because of marketing schemes, discounts, taxes...
So I think it would be great if I could write code such as the code below, so that I could change the script at runtime.
public BigDecimal calculate(String script) {
return (BigDecimal) ScriptEngine.execute(script);
}
Is there any way to implement this using Java?

Yes: Use the Scripting API.
There are implementations to run scripts written in JavaScript, Groovy, Python and lots of other languages.
[EDIT]
Since it was mentioned in the comments: Be wary of security issues.
There are several options:
You allow end-customers to supply scripts (say in a web form)
You don't allow customers to supply scripts; if a script needs to be changes an administrator or developer must start a specific tool.
You develop a system which only allows to execute "safe" scripts
Option #3 doesn't work (= only works for the most simple cases). There is a mathematical proof that a computer program can never tell what another program can potentially do without actually executing it.
So you can get away with option #3 if you don't allow to call methods (or only a very, very limited set of methods). But most scripting languages allow to access Java classes which means you can eventually get System.exit() or Runtime.exec(). This in turn means you have to write a parser which makes sure that the code doesn't contain something odd.
Which you will have to update every day because the customers will come up with new ... err ... interesting ways to use the feature.
Also chances are that you'll make a mistake - either the parser won't accept valid input or it will let malicious code pass. Given the complexity of the problem, the chance is between 99.9999% and 100%.
Option #1 means no security at all but after the third change, customers will berate you to adopt it. It will work for some time until the first script kiddie comes along and ruins everything. Guess whose fault that will be? The manager who hired his nephew... the kid?
So a human will have to eyeball the scripts, fix all the bugs in them and configure the system to run them. Option #2 will cause all kinds of griefs, too, but it will cause less grief, all things considered.

What language do you want "script" to be in?
One way to do this would be to use Javascript, and use a library like Rhino. This will let you execute some JS and get the output inside your code.
http://www.mozilla.org/rhino/

Sure, see Mozilla Rhino

You can use beanshell.jar - It is a standalone shell as well, but can easily be used to run uncompiled java code at runtime.

Related

Why and how do you use JShell?

I went through a couple of tutorials for JShell and I still do not understand the most important part: why would I even use JShell?
Here what Oracle says:
"You can test individual statements, try out different variations of a
method, and experiment with unfamiliar APIs within the JShell
session".
Yes, great, but for all those things I can just use an IDE. I do understand, that REPL should make code evaluation faster. However, testing a snippet of code in IDE in a dummy Hello World project with Sysout is for sure not slower?
In fact, IDEs provide autocomplete, detect errors early and I can checkout an implementation of a method/class with a mouse click. This all should make code testing in IDE faster than in JShell?
What am I missing?
Can someone give me a couple of use cases, where using JShell is better then using IDE?
How do you guys use JShell?
Though I would really encourage you to go ahead and read The Java Shell motivation and goals.
Yet to answer your question with a slight hands-on and I would actually be glad to know about the time you take and procedure you would follow while trying this out on an IDE. So, with few those, here you go:-
1. I recently got to know that Java 9 introduced overloaded Convenience Factory Methods for Collections and then was curious about what do they do and how do I make use of them.
Steps
-> Type 'jshell' on command prompt (assuming JAVA_HOME is set to JDK9's bin)
-> Type 'List.o'
-> Press Tab (completes the `of`)
-> Tab displays all signatures
-> Tab starts reading the documentation from first
2. How about persisting the syntax of the code? If you would have noticed in the above image the initialization of the List didn't even bother to care about the variable to store it in, terminating semi-colon etc.
3. How quickly can you find out the exceptions thrown by some piece of code that you are about to implement? So, a use case here, I want to create a Map of String(name of fruits) to String(their color), then add some more fruits to it in the later phase and leave out those colors which I am not certain about. Then finally get a list of all those fruits which are Red. And of course, since I am learning Java 9 these days, I would try to use as much of APIs as from Java9.
And while you would try adding all of that(^^) code in your IDE, you can yourself notice the time you would eventually take to realize all those characteristics of Immutable Map Static Factory Methods.
PS:
Robert has presented Jshell here which is a detailed view of how all can the JShell be effective.
As you do all of the above, do keep in mind that it's not a goal of Jshell to be an IDE.
And all of that, in general, does simple experimentation with a language by bypassing the compile stage of the "code -> compile -> execute" cycle. read-eval-print-loop

Test if java-code does NOT compile

It might sound a little bit weird, but I am looking for a possibility to test if some statements in the code are rejected by the typechecker (which means that the code should NOT compile).
Be explain my intend: I am running a controlled experiment on type-systems where my subjects have to write some methods in java for me. The functionality of the methods written by the subjects can be easily tested using unit-tests, but I also want the methods to be well-typed (which means that some methodcalls should not be allowed).
One way I could imagine to achieve that would be writing the statements which should break the build into a seperate file, add it to the classpath and run javac to see if any error occurs during the build. Although this might work, it does not feel very sophisticated, so my question is: Is there any better way to (automatically) test if some statements are refected by the typechecker?
This is a variation of the Halting Problem, which isn't solvable in the general case. To do this, you have to run (or in this case compile) the code. Therefore, the solution you've already proposed is the best solution.
Have you looked at the Checker Framework? It can be used to static code analysis and more. It might be a good fit for what's you are doing. Here is the link on my answer with an example of the annotation type processor.
Also you may find the Java Compiler API quite helpful. It allows to execute javac programmatically in a single java machine. So you could use it as a part of your tests.

can access to standard java libraries be blocked by prohibiting import statements and java.* strings?

suppose I want to allow people run simple console java programs on my server without ability to access the file system, the network or other IO except via my own highly restricted API. But, I don't want to get too deep into operating system level restrictions, so for the sake of the current discussion I want to consider code level sanitization methods.
So suppose I try to achieve this restriction as follows. I will prohibit all "import" statements except for those explicitly whitelisted (let's say "import SanitizedSystemIO." is allowed while "import java.io." is not) and I will prohibit the string "java.*" anywhere in the code. So this way the user would be able to write code referencing File class from SanitizedSystemIO, but he will not be able to reference java.io.File. This way the user is forced to use my sanitized wrapper apis, while my own framework code (which will compile and run together with user's code, such as in order to provide the IO functionality) can access all regular java apis.
Will this approach work? Or is there a way to hack it to get access to the standard java api?
ETA: ok, first of all, it should of course be java.* strings not system.*. I think in C#, basically...
Second, ok, so people say, "use security manager" or "use class loader" approaches. But what, if anything, is wrong with the code analysis approach? One benefit of it to my mind is the sheer KISS simplicity - instead of figuring out all the things to check and sanitize in SecurityManager we just allow a small whitelist of functionality and block everything else. Implementation-wise this is a trivial exercise for people with minimal knowledge of java.
And to reiterate my original question, so can this be hacked? Is there some java language construct that would allow access to the underlying api despite such code restrictions?
In your shoes I'd rather run the loaded apps inside a custom ClassLoader.
Maybe I'm mistaken, but if he wants to allow limited access to IO through his own functions, wouldn't SecurityManager prevent those as well? With a custom ClassLoader, he could provide his SanitizedSystemIO while refusing to load the things he doesn't want people to load.
However, checking for strings inside code is definitely not the way to go.
You need to check the SecurityManager. It is called by lots of JVM classes to check, before they perform their work, if they have the permission needed.
You can implement your own SecurityManager. Tutorial.

Dump execution - java?

Is it possible to dump the complete program execution in java? I have to go through a complete process flow for a execution for a specific input values. Using step over, step into is a bit time consuming and I wanted to find out if any java command dumps the execution?
Maybe you want to have a look at the Chronon Time Travel Debugger.
I haven't tried it out yet, after a long beta period it seems to be now officially available and may satisfy your demands. It's a commercial product, but offers a free time trial.
Another alternative may be the use of debugging to a core file using the jsadebugd utility provided with the JDK. (you can't step forwards and backwards, but you can examine the stack/monitors of all threads which might help you already out)
If you only need the method calls, as stated in a comment, maybe a profiler which uses instrumentation like jprofiler or yourkit will also be helpful.
Or you want to have a look at btrace, a dtrace-like tool.
If you're able to modify/build the application, also some sort of a small AOP method interceptor will do the job.
If I understand correctly, you want something like a view of all the method calls that happen when your program processes some set of inputs. You can often get this kind of information out of a profiler, such as JProbe:
http://www.quest.com/jprobe/
You can run the program under JProbe, and then it will present a visual call graph of all of the method calls or a list of all method calls along with their frequency of execution.
Somewhat related are static analysis tools, such as Understand:
http://www.scitools.com/
Static analysis tools tend to focus on figuring out overall code structure rather than what happens with a specific set of inputs though.
Of course, you can always change code, but it's probably too much work to change every method in a large system to print a debugging string. Aspect-oriented programming tends to be a good approach for this kind of problem, because it's a cross-cutting concern across the codebase. There are a few different Java AOP solutions. I've used Spring AOP with dynamic proxies, which isn't enough to cover all method executions, but it is good enough for covering any method execution defined on an interface for a bean managed in a Spring container:
http://static.springsource.org/spring/docs/3.1.0.M1/spring-framework-reference/html/aop.html
For example, I've written a TimingAspect that wraps the execution of a method and logs its execution time after it completes. When I want to use it, I update my Spring applicationContext.xml to specify pointcuts for the methods I want to measure. You could define a similar TracingAspect to print a debugging message at the start of each method execution. Just remember to leave this off for production deployment.
For all of these approaches, measuring every single method call is probably going to cause information overload. You'll probably want to selectively measure just a few important pieces of your own codebase, filtering out core JDK methods and third-party libraries.

Is code injection possible in Java?

nowadays you can read much about code injection, exploits, buffer-, stack- and heap-overflows etc. leading to inject and run code. I wonder what of this stuff is relevant for Java.
I know, there are no pointers in the Java language. But doesn't the JVM organize data in heaps and / or stacks?
I know there is no eval function (like in PHP) so you cant easily use an input as Java-code. I am not so sure whats going on on bytecode level.
I think XSS is possible, for example in an Java EE application, when no inputs are filtered. But isn't this more a JavaScript injection, because the injected code runs in the browser and not in the JVM?
So which code injections are possible with java and which are not? And is this true for other Java platform languages, too?
Thanks in advance.
A java program itself is pretty much not vulnerable to code injection. However, all the native code that supports the app is vulnerable to all the different kinds of code injection - this includes the JVM and all native code parts in the app or its libraries.
Also, there are a few more things to consider:
Anything where java is used as a gateway to other systems is possible:
SQL Injection
XSS (which is in the end nothing more than JavaScript Injection)
If the java program is itself a interpreter/compiler of some kind, it might be possible to inject code into your interpreted language/compiled program (this includes using your program as a java compiler...)
And of course if you can get the java program to write a file to disk that contains code (be it native, java or something else) you might be able to get it executed by other means (which can be a different vulnerability in your app, the os or another app) - this is not direct code injection but quite similar in effect.
If the server application creates bytecode at runtime (for example with BCEL or Javassist), and if this creation can be influenced by user input, then a code injection is possible.
However, if you application uses no magic (which should be 99% of all applications), it will not be possible.
There are a couple ways in which Java code could be injected into an application such as using the scripting API or dynamic JSP includes.
The code below allows a user to inject arbitrary Javascript into Java's script engine.
import javax.script.*;
public class Example1 {
public static void main(String[] args) {
try {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
System.out.println(args[0]);
engine.eval("print('"+ args[0] + "')");
} catch(Exception e) {
e.printStackTrace();
}
}
}
In this case, the attacker decides to inject code that creates a file on the file system.
hallo'); var fImport = new JavaImporter(java.io.File); with(fImport) { var f = new File('new'); f.createNewFile(); } //
check owasp website for more examples
You could write a web service that accepted a Java code snippet, wrapped it in a class/method declaration, saved it to disk, ran the compiler on it and then dynamically loaded and executed the result. So code injection is certainly possible.
But with typical Java implementations, it's perhaps not very efficient because of the relatively heavyweight compilation process (it might still be practical for some apps though).
Code injection is highly relevant with SQL because the "first guess" of many beginners is to use string concatenation to insert variables into a statement. But it rarely crops up as an idea amongst Java programmers. So that's the reason it isn't much of a concern.
If Java compilers become exposed as light-weight library services, then you'd have something much closer to the equivalent of eval and therefore it might start to become a relevant concern.
If it was possible, Java would already have been dead for long.
On the other hand, SQL injections are very easy to avoid by using PreparedStatement to store user-controlled input and XSS is also very easy to avoid by using <c:out/> for (re)displaying user-controlled input at the webpage.
Unless you are doing weird things on the server (like dynamically generating code, etc), it is impossible to bo vunerable for code injection.
Although I can think of an (ugly) situation where the application dynamically creates a JSP based on user input. That JSP will be translated to Java code, which is being compiled to byte-code by the web container, and then executed. This could introduce an injection point. But generating JSP's dynamically normally doesn't make any sense.
You can't inject Java. But if you are not careful, people could inject Javascript (i.e. XSS as you mention) or SQL. There are heaps and stacks, but no way to get to them.
You can't inject java, but all web applications are vulnerable to XSS if the input is not properly filtered. Also any application that interacts with a sql database can be vulnerable to SQL injection. To avoid this you will want to look into Parameterized Queries.
It is certainly more difficult, if you compare it to interpreted languages. However, the JVM supports scripting languages like JavaScript, and one of the example above demonstrates injection when JavaScript is at play.
The JVM also supports scripting with Groovy, which is the the Java scripting equivalent. So, if you know that this is what is happening behind the scenes, you can use something similar to this:
Class scriptClass = new GroovyClassLoader().parseClass( new File( "test.groovy" ) ) ;
Of course, you will have to get test.groovy on the server somehow, which is another story. See this thread for more details: Calling a Groovy function from Java. Groovy compiles to byte code on the fly and it is automatically loaded into the JVM.
I've seen enterprise applications written in Java expose a Scripting Web Console, where you could supply an entire Groovy file and execute it with the system still running ... with Admin privileges. Behind it uses the JVM's scripting capabilities. You could also use it with JavaScript.
Here are the scripting languages supported by the JVM as of July, 2020:
Java
Kotlin
Scala
Groovy
Clojure
Fantom
Ceylon
Jython
JRuby
Frege
Xtend
Golo
Concurnaas
Yeti
See this article for more details.
Bottom line, code injection in Java is not as easy as it is in other languages, especially interpreted ones, like JavaScript, Ruby, PHP, etc.

Categories