In a huge project with tens of thousands of Java files there are a couple of Java classes where developers may pass in strings as parameters to a constructor class I had implemented
public byte[] getProductReport(List<String> products, Date from, Date to) {
// ... do some stuff before...
List<ReportParameterDto> reportParameters = new ArrayList<>();
reportParameters.add(new ReportParameterDto("From (YYYY.MM.DD)", ParameterType.DATE, from));
reportParameters.add(new ReportParameterDto("To_(YYYY.MM.DD)", ParameterType.DATE, to));
reportParameters.add(new ReportParameterDto("Products", ParameterType.SELECT, someList));
return ReportFromCRServerHelper.downloadReport("ProductReporot", reportParameters, ReportFormat.PDF);
}
If a developer uses wrong string values downloading a requested report (from a remote Report server) will fail during runtime.
In this example I would like to have some validation checking - during compilation - in order to avoid these errors before they are found by the customer.
I have API methods to obtain parameter values from a report which I hope to use
during compilation of the above method.
In my example the compilation should fail and throw an error highlighting how parameters should look instead:
"From (JJJJ-MM)" is invalid --> should be "From_(JJJJ-MM)"
"Products" is invalid --> should be "PRODUCT_LIST"
Can I detect these parameters (used in above ReportParameterDto constructors) through JAVAX annotation processing?
The few tutorials / blogs that I found dealt with validating parameters in method signatures, not the values passed into methods.
Or are there a more elegant tools available?
A compile-time tool like the Checker Framework can validate the arguments to a method or constructor. You annotate the parameter types to indicate the permitted values, and then when javac runs it issues a warning if an argument may not be compatible with the parameter.
If there is a limited number of possible values, then you can use the Fake Enum Checker to treat strings or integers as enumerated values. (Using a Java enum is also a good idea, but may not be possible or convenient because of other code that expects a string or integer.)
If the number of possible values is unlimited, then you can use the Constant Value Checker -- for example, to supply a regular expression that any constant string argument must satisfy.
You can also define your own compile-time validation if you want different functionality than is available in the checkers that are distributed with the Checker Framework.
Related
In the following expression:
T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime)
.getRuntime().exec(T(java.lang.Character).toString(105)
.concat(T(java.lang.Character).toString(100))).getInputStream())
Does the '105' in toString(105) refer to an itemized object within the Character class?
and
Why is the 'T', which I believe expresses a generic type, and is used 4 times in this expression, a necessary feature of Java?
The toString() method that seems to be invoked here is actually the toString(char) (static) method of java.lang.Character. Quoting the documentation:
public static String toString(char c)
Returns a String object representing the specified char.
The result is a string of length 1 consisting solely of the specified char.
Parameters:
c - the char to be converted
Returns:
the string representation of the specified char
Since:
1.4
Note that 100 and 105 are also valid char values where 100 == 'd' and 105 == 'i'.
Update: after knowing the context, I am now confident that this code is intended to be injected into a template for a web page. The template engine used provides special syntax for accessing static methods where T(Classname) resolves to just Classname (not Classname.class!) in the resulting Java code.
So your code would be translated to:
org.apache.commons.io.IOUtils.toString(java.lang.Runtime
.getRuntime().exec(java.lang.Character.toString(105)
.concat(java.lang.Character.toString(100))).getInputStream())
The full qualification of the class names is necessary because we do not know if those classes are imported on the attacked site (or if the template engine even allows imports or class names must always be fully qualified).
A more readable version of the code that assumes imports is
IOUtils.toString(
Runtime.getRuntime().exec(
Character.toString(105).concat(Character.toString(100))
).getInputStream()
)
And after a little de-obfuscation...
IOUtils.toString(Runtime.getRuntime().exec("id").getInputStream())
Whatever this is, it is definitely NOT meaningful Java code.
And the fact that you can provide it as as a search query on some site is not evidence that it is Java either.
I suspect that this is actually some custom (site-specific?) query language. That makes it futile to try to understand it as a Java snippet.
Your theory that T could denote a generic type parameter doesn't work. Java would not allow you to write T(...) if that was the case.
Furthermore, if we assume that org.apache.commons.io.IOUtils, java.lang.Runtime and so on are intended to refer to Java class objects, then the correct Java syntax would be org.apache.commons.io.IOUtils.class, java.lang.Runtime.class and so on.
So what does it mean?
Well a bit of Googling found me some other examples that look like yours. For instance;
https://github.com/VikasVarshney/ssti-payload
appears to generate "code" that is reminiscent of your example. This is SSTI - Server Side Template Injection, and it appears to be targeting Java EE Expression Language (EL).
And I think this particular example is an attempt to run the Linux id program ... which would output some basic information about the user and group ids for the account running your web server.
Does it matter? Well only if your site is vulnerable to SSTI attacks!
How would you know if your site is vulnerable?
By understanding the nature of SSTI with respect to EL and other potential attack vectors ... and auditing your codebase and configurations.
By using a vulnerability scanner to test your site and/or your code-base.
By employing the services of a trustworthy IT security company to do some penetration testing.
In this case, you could also try to use curl to repeat the attempted attack ... as the hacker would have done ... based on what is in your logs. Just see if it actually works. Note that running the id program does no actual damage to your system. The harm would be in the information that is leaked to a hacker ... if they succeed.
Note that if this hack did succeed, then the hacker would probably try to run other programs. These could do some damage to your system, depending on how how well your server was hardened against such things.
I'm trying to execute this string in java using reflection
String methodCall = "com.mypackage.util.MathUtil.myFunction(4,\"abc\")";
This code does the job for me (after little string parsing)
Class.forName("com.mypackage.util.MathUtil").getDeclaredMethod("myFunction", int.class, String.class).invoke(null, 4, "abc");
The problem with the above solution is that i need to know the parameter types before invoking the method, and unfortunately i don't have them.
As a solution i can get all declared methods using Class.forName("com.mypackage.util.MathUtil").getDeclaredMethods() , iterate, match name and parameter count, and manually check types with some logic to identify the appropriate method.
Can java do this heavy lifting for me with something like this
Class.forName("com.mypackage.util.MathUtil").getDeclaredMethod("myFunction").invoke(null, 4, "abc");
This code should try to match the appropriate method and can throw NoSuchMethodException or Ambiguity error when 2 or more similar methods matched. Also feel free to suggest other ways to achieve this use case.
The core problem of identifying the appropriate method with types was eliminated with the help of BeanShell.
String methodCall = "com.mypackage.util.MathUtil.randomNumbers(4,\"abc\")";
Interpreter i = new Interpreter();
String result = i.eval(methodCall).toString();
The performance of this eval execution is actually pretty good (~10-20ms) and i'm using this solution on a standalone framework, so i need not worry much. This also gives me an additional benefit to allow a complete java snippet on the framework for customisation purposes.
Special Thanks to #jCoder for the solution.
I wish to translate an OData query into a MongoDB query. I have the olingo-odata4 code and have isolated the calls necessary to take an input string e.g.
Name eq 'Buzz' and (amount gt 1.99 or size lt 10)
and run it through ExpressionParser with my own ExpressionVisitor implementation to intercept the various parse states like visitLiteral and visitBinaryOperator, etc. From there it is trivial to construct the equivalent MongoDB query. My main is essentially a trimmed down copy of the odata test drivers, including the mocking of the Edm class for startup:
ExpressionParser ep = new ExpressionParser(mock(Edm.class), odata);
My challenge is that I cannot seem to set up the environment properly for the parser to recognize fields, e.g. members. I would have hoped that Name eq 'Buzz' would cause the visitMember method to be called for Name but it does not; instead, I get a parse fail with the message: Property paths must follow a structured type.
So my overall question becomes: If the $filter argument to OData shows the expression syntax as Name eq 'Buzz' then what has to happen in the server implementation to recognize Name as a member?
The parser is unfortunately too closely coupled to the data model, IMHO. The test drivers I looked at were mostly {5 eq 5} and things like that so I was led astray. The property path test driver, however, cannot mock the EDM; it must construct a model in order to declare the type (string, etc.) of the fields. This is why visitMember Member class has the getType() method. But this means you cannot use the parser to just crack the syntax and dynamically perform actions on the results.
I ended up just creating a very small grammar in ANTLR to parse the OData query expressions and it was easy to convert to MongoDB query language.
I'm currently trying to set some parameters from an external system. I have a request with named parameters, and in order to properly set the variables, I'm using annotated method arguments on my service calls. A simplified example might be
public Response loginAttempt(#MyParam("username") String username, #MyParam("password") String password) {
// login logic here
}
Clearly, annotating each argument name is annoying and duplicative (although, it does have the minor advantage of allowing me to change the name over different versions of the API, that's beside the point.)
It would be very, very handy if I was able to, in my reflective portion, to simply reference the name of the argument. Where now, I get the arguments and their annotations, note their order, make an array of that order, and run with it.
I know in previous version of Java this simply cannot be done. I also know Java is releasing versions faster than ever before, with newer and more modern features than ever before. Unfortunately, the signal to noise ratio with 15 year old information is too just not high enough to get a definitive answer. Is this something that can be done with modern Java?
Since Java 8 if you compile your code with javac -parameters option and the method parameters will be retained, however there are drawbacks. The problem is primarily the class file size, take a look at Obtaining Names of Method Parameters docs.
You can use java.lang.reflect.Parameter.getName() to get the method parameter name:
Method m = getClass().getMethods()[0];
System.out.println(m.getName()); // loginAttempt
Parameter[] parameters = m.getParameters();
for (Parameter parameter : parameters) {
System.out.print(parameter.getName() + " "); // username password
}
I'm working on annotation processor for Kotlin and because the processed elements are in Java I don't receive nullables as ? instead with a #Nullable annotation and that's fine, but I'm facing a problem with receiving null parameters in types and in higher order functions, for normal parameters.
var someNullField: String? = ""
I will receive java.lang.String at process with #org.jetbrains.annotations.Nullable in its annotations.
But List<String?> for example will return me java.util.List<java.lang.String> without any annotations not in the main element not in the type arguments which results in a unknown nullability state
I tried using javax.lang.model.util.Types to find some sort of result but nothing.
Some of the code that i'm using now:
val utils = processingEnvironment.typeUtils
val type = fieldElement.asType()
if (type is DeclaredType) {
val typeElement = utils.asElement(type)
type.typeArguments
.forEach {
//Trying different ways and just printing for possible results
val capture = utils.capture(it)
val erasure = utils.erasure(it)
val element = utils.asElement(it)
printMessage("element: $element isNullable: ${element.isNullable()} isNotNull: ${element.isNotNull()}\ncapture: $capture isNullable: ${capture.isNullable()} isNotNull: ${capture.isNotNull()}\nerasure: $erasure isNullable: ${erasure.isNullable()} isNotNull: ${erasure.isNotNull()}")
}
}
All help will be appreciated.
A bit of necessary history: as of Java 6 (when the Mirror API was made public) Java annotations could not be used on anything, but the same kinds of top-level elements, accessible via reflection. You could annotate classes, methods and fields, but could not annotate type arguments (List<String>) or local variables (String value = ...). Sun/Oracle engineers have acknowledged that limitation, and in Java 8 the so-called "type annotations" were born.
Type annotations can target type of anything: type of local variable, array component type, type variable type and even return type (later annotation is placed similarly, but is distinct from the old-school annotations on the method!). Type annotations are created via new #Target value: ElementType#TYPE_USE.
When Kotlin people write
List<String?>
That really means
List<#Nullable String>
which can be read as: "the list of nullable String elements".
Since the type itself is being targeted, you are expected to obtain annotations by examining it's original TypeMirror (don't bother with erased or captured TypeMirrors, they don't have enough connection to source code to retain the annotations). Coincidentally, the Mirror API was refactored, resulting in the new interface AnnotatedConstruct, and conveniently making TypeMirror it's descendant.
Now the bad news: by the time of Java 8 release the support for inspecting type annotations apparently wasn't production-ready, so it got butchered. The JSR has been rewritten to imply, that "TypeMirror#getAnnotationMirrors" is supposed to return nothing.
The bits of support, that were removed from public API, are still available via Oracle's vendor-specific Tree API (supported in javac only). The TypeMirror, returned by Tree#getTypeMirror may contain the annotation the way you are expecting it to. But since it is buggy, you will only be able to get annotations via series of hacks, and ultimately, this won't work at all times (such as in case of nested type arguments). See this question for some research in that direction.
The fix for that mess was merged in Java 9. I haven't tested it yet, but it looks like TypeMirror#getAnnotationMirrors might finally work. There are no plans to backport the fix to the older Java version.