I want to give the user the possibility of writing symbolic maths formulas which are later evaluated with certain values.
The user might - for example - want to enter some formula a * (b + 1) where a and b may be different upon each evaluation. My approach so far was using the built in JavaScript engine in Java but as I read through this tutorial on scripting, I realized that the engine is actually really powerful.
The formulas are stored in configuration files, so someone might send such a configuration file to another user, which would then be executed on their machine.
Unfortunately I don't know JavaScript, so I don't know if the user could actually inject any seriously malicious code.
The formula above would be stored as a JavaScriptFormulaProcessor object like this:
JavaScriptFormulaProcessor processor =
new JavaScriptFormulaProcessor("a * (b + 1)", "a", "b");
Initializing the engine:
public JavaScriptFormulaProcessor(String formula, String... variableNames) throws ScriptException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
StringBuilder builder = new StringBuilder(variableNames[0]);
for (int i = 1; i < variableNames.length; i++) {
builder.append(", ").append(variableNames[i]);
}
String script = "function f("+builder.toString()+") { return "+formula+"}";
engine.eval(script);
invocable = (Invocable) engine;
}
Executing the function:
public void execute(Number[] functionInputs) throws ScriptException {
try {
Object result = invocable.invokeFunction("f", functionInputs);
// process result..
} catch (NoSuchMethodException e) {
throw new RuntimeException(e); // should actually never be thrown..
}
}
Does this code create an attack vector for my application? Bonus question: if yes, any better suggestions?
If formula is under the users' control, then this code is extremely vulnerable because Java methods can be accessed and run from within the ScriptEngine.
See also this question: Why can you execute Java-Code from a JS-ScriptEngine eval(String)?
As an example, consider this formula:
String formula = "(java.lang.Runtime.getRuntime().exec('some-malicious-script'), a+b)";
Apart from calculating the sum, this script would run java.lang.Runtime.getRuntime().exec().
You can run any static Java method this way.
I would say that this code is not safe as you allow JavaScript to be evaluated by the engine.
What I would do:
Send the config file to a server, where the receiver gets the config file from. Write a parser server side that only accepts valid formulas and discards anything that isn't, then store it somewhere (database / file / whatever). Then send a 100% safe package that you made yourself after parsing to the receiver. This way you assure that whatever the receiver gets is firstly validated by you.
NOTE: If you do this, you need to write some sort of converter in javascript that converts your package to the javascript - formulas in order for it to be evaluated by the code that you present in your question. You could choose to only validate server side, and then just send the user-made package originally sent to the receiver, though you'd allow yourself to make a mistake in validating causing the receiver to still run unsafe code.
Related
I'm trying create a simple UI here on my iOS app to test a thing or two out but I'm having some issues here. My app is set up with a UITextField and UIButton. I'm trying to replace a string on my .js file which is saved on my virtual server. In my .js file I have below:
// Prepare a new notification
var notification = new apn.Notification();
// Display the following message (the actual notification text, supports emoji)
notification.alert = 'Hi James';
I basically would like to replace "Hi James" with whatever I typed in the UITextField in my Swift 3 project but not too sure where to start. This would be my first time sending data to .js file so anything would help. I'm thinking so far that it'd be something along the lines to below. Node.js would be similar to Javascript since it's cross platform.
func sendSomething(stringToSend : String) {
appController?.evaluateInJavaScriptContext({ (context) -> Void in
//Get a reference to the "myJSFunction" method that you've implemented in JavaScript
let myJSFunction = evaluation.objectForKeyedSubscript("myJSFunction")
//Call your JavaScript method with an array of arguments
myJSFunction.callWithArguments([stringToSend]) }, completion: { (evaluated) -> Void in
print("we have completed: \(evaluated)")
})
}
Found that on a relevant StackOverflow post so I feel like I'm getting close. Any assistant would be appreciated in advanced. Have a good one!
I recommend using the Node HTTP or ExpressJS server reading the POST fields and posting a document from your iOS app with the desired field
See
https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/
I am trying to encode < and > in a MVC parameter, tried using encodeURIComponent, however the decoding seem to occur prior to reaching the controller and it blows up the routing
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Default",
"Home/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
http://localhost/HomeStretch/Home/ListAll?Value=%22%7B%3Cdbid%3E%7BD576959C-31F8-469B-9C23-17B046DF590F%7D%3Cdbid%3E%7D%22"
If I take away the <> carets it works, if I leave them in the call fails. I can do my own silly conversion using a * instead of %, however I am wondering if there is a better way of getting around this?
Turns out this maybe a security issue, I was scouring the event log and found below exception had been thrown. How do I properly insulate my tags, so this won't happen?
Exception information:
Exception type: HttpRequestValidationException
Exception message: A potentially dangerous Request.QueryString value was detected from the client (Filters[0].Value=""{<dbid>{D576959C-31F8...").
at System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection)
at System.Web.HttpValueCollection.GetValues(String name)
Rethink why you're sending the information in this format. The string you show translates to:
Value="{<dbid>{D576959C-31F8-469B-9C23-17B046DF590F}<dbid>}"
ASP.NET is trying to protect you from hackers that might be attempting an injection attack. It sees <dbid>, and it thinks they're probably trying to send HTML to your server.
If you really need to support this sort of input, then you can use the [AllowHtml] on your action to tell ASP.NET that you'll be super careful not to let this input get used without being properly encoded.
But I'd strongly recommend re-thinking why you're sending the information in this way. It seems to me that dbid=D576959C-31F8-469B-9C23-17B046DF590F might work, or perhaps Value={"dbid": "D576959C-31F8-469B-9C23-17B046DF590F"}.
I am developing a fat client page based on Javascript that will allow users to carry out tasks outwith another web client application (Oracle Siebel).
The way the web page will be called from the browser will be by a simple window.open() call.
When this happens a URL will be passed which contains some parameters at the end which will change the functionality of the fat client page depending on what value they have.
e.g
userlevel=1 //normal user
userlevel=2 //advanced user
In an example full URL would be like so
www.mypage.com/index.htm?id=25215125%userlevel=2%context=full
However a user who wants to change their access only need to figure out that if they change their user level then they can change their access rights on this fat client page.
Yes, I know this is risky and before you ask why I am not using a server supported thin client with controls that cannot be altered by the user. I simply have to do it this way!
This system will be in a "trusted" environment and this users will have at best average IT skills.
So all I need to do is figure out a way to obfuscate/ scramble the URL parameters (if possible) and then decipher them at the fat client.
e.g.
www.mypage.com/index.htm?1sdf908ga90-821098650f8asdg098g0a98
I tested it out on the browser and no complaints so far so I guess I just need to develop a piece of logic to decipher it.
e.g. I could use MD5?
Any examples or ideas?
Thanks
Try Base64 encoding it. https://stackoverflow.com/a/4699739/1088652
That'll shorten it and obfuscate it, so that users can't just throw values in the URL.
Params integrity can be ensured with HMAC. You generate hash using secret key and all the params, you include this hash inside of URL, then at server side you generate hash using same params and compare values.
function generateSignature(array $params, $hmacKey)
{
// sort the array by key using SORT_STRING order
ksort($params, SORT_STRING);
$escapeFunc = function ($val) {
return str_replace(':', '\\:', str_replace('\\', '\\\\', $val));
};
// generate the signing data string
$signData = implode(':', array_map($escapeFunc, array_merge(array_keys($params), array_values($params))));
// base64-encode the binary result of the HMAC computation
$merchantSig = base64_encode(hash_hmac('sha256', $signData, pack("H*", $hmacKey), true));
return $merchantSig;
}
I'll preface this by stating that I know Java is not JavaScript and vice versa.
I've got a project where I need to count occurrences of words for each of 1750 document names and document contents. I've got some awesome JavaScript from a colleague that does exactly what I want from a form input on a web page.
I want to use Java's FileReader, BufferedReader, walkFileTree, etc. to traverse the directories in which the documents live.
I'm not sure if this is the most efficient or effective approach, but both the Java and JavaScript parts of the code are working independently of one another now, and I'd like to see if I can get them to pass data between them before I start re-inventing the wheel.
Here's where I am so far. I'm stuck at the CLParse method & have inserted pseudocode:
public static void main(String... aArgs) throws FileNotFoundException {
File startingDirectory= new File("CGT");
List<File> files = FileListing.getFileListingNoSort(startingDirectory);
for(File file : files ) {
CLParse(file.toString());
} }
static private List<File> getFileListingNoSort(File aDirectory) throws FileNotFoundException {
List<File> result = new ArrayList<File>();
File[] filesAndDirs = aDirectory.listFiles();
List<File> filesDirs = Arrays.asList(filesAndDirs);
for(File file : filesDirs) {
result.add(file); //always add, even if directory
if ( ! file.isFile() ) {
List<File> deeperList = getFileListingNoSort(file);
result.addAll(deeperList);
} }
return result;
}
/* is something like this doable and how would I do it?
*/
public static void CLParse(String fn) {
pass fn to JavaScript counter
return an array of {word,occurences} for the string
write array to file
}
I'll be creating another set of methods to extract and pass the document CONTENTS as a string as well. I'd love to know if anyone has any practical experience passing values back and forth between Java and JavaScript, and advice on a good/better way to do it.
You got 2 Options to let them interact with each other, which i know:
1.Applet <-> javascript
2.Serlvet <-> javascript
With option 1, you have to build a Communication with a JSObject: JSObject
or you cann call the Applets Method instanstly with document.appletname.methodname();
with this you can even Parse same simply Formats to each other.
With Option 2 you have to build a communication with a Servlet.
in here you have to send an Ajax request to the the Servlet:
$.post('login',{name:"Peter", pw:"123456"},function()
{
//do whatever
})
JavaServlet class
the first comment, has to written as an Servlet in your web.xml, it´s the servlet pattern.
the second ones, are the parameters which can be read in the servlet. the function describes the stuff, which can be done in the request.
The differences between these two Options are:
1.the Applets runs on the users Computer, so you can access his files. But for this your applet has to be signed.
2.the Servlet runs on the Server. Here you have got full file access(if the system allows you too have it).
I would try to investigate Mozilla Rhino.
http://en.wikipedia.org/wiki/Rhino_%28JavaScript_engine%29
Check out Rhino https://developer.mozilla.org/en-US/docs/Rhino
You can create java objects and use them in javascript. Integration is straightforward
You can use AJAX to send and receive values to server. You can send parameters or JSON to server and get response.
You can use JSONP to serve the data, or if you have no control of the second server, use a reverse proxy to proxy requests to the second server through the first.
I am making an AJAX chat room with the guidance of an AJAX book teaching me to use JSON and eval() function.
This chat room has normal chat function and a whiteboard feature.
When a normal text message comes from the php server in JSON format, the javascript in browser does this:
Without Whiteboard Command -------------------------------------------
function importServerNewMessagesSince(msgid) {
//loadText() is going to return me a JSON object from the server
//it is an array of {id, author, message}
var latest = loadText("get_messages_since.php?message=" + msgid);
var msgs = eval(latest);
for (var i = 0; i < msgs.length; i++) {
var msg = msgs[i];
displayMessage(escape(msg.id), escape(msg.author), escape(msg.contents));
} ...
The whiteboard drawing commands are sent by server in JSON format with special user name called "SVR_CMD", now the javascript is changed slightly:
With Whiteboard Command --------------------------------------------------
function importServerNewMessagesSince(msgid) {
//loadText() is going to return me a JSON object from the server
//it is an array of {id, author, message}
var latest = loadText("get_messages_since.php?message=" + msgid);
var msgs = eval(latest);
for (var i = 0; i < msgs.length; i++) {
var msg = msgs[i];
if (msg.author == "SVR_CMD") {
eval(msg.contents); // <-- Problem here ...
//I have a javascript drawLine() function to handle the whiteboard drawing
//server command sends JSON function call like this:
//"drawLine(200,345,222,333)" eval() is going to parse execute it
//It is a hacker invitation to use eval() as someone in chat room can
//insert a piece of javascript code and send it using the name SVR_CMD?
else {
displayMessage(escape(msg.id), escape(msg.author), escape(msg.contents));
}
} ...
Now, if the hacker changes his username to SVR_CMD in the script, then in the message input start typing javascript code, insdead of drawLine(200,345,222,333), he is injecting redirectToMyVirusSite(). eval() will just run it for him in everyone's browser in the chat room.
So, as you can see, to let the eval to execute a command from an other client in the chat room is obviously a hacker invitation. I understand the book I followed is only meant to be an introduction to the functions. How do we do it properly with JSON in a real situation?
e.g. is there a server side php or .net function to javascriptencode/escape to make sure no hacker can send a valid piece of javascript code to other client's browser to be eval() ? Or is it safe to use JSON eval() at all, it seems to be a powerful but evil function?
Thank you,
Tom
What is this book? eval is evil, there is not a single reason to use it, ever.
To transform a JSON string into a javascript object, you can do the following:
var obj = JSON.parse(latest)
Which means you can then use:
[].forEach.call(obj, function( o ) {
// You can use o.message, o.author, etc.
} )
To do the opposite (javascript object -> JSON string), the following works:
var json = JSON.stringify(obj)
It only is unsafe if the executed code is generated by other clients and not by the server. Of course you would need to prevent anybody to use that name, though I don't understand why you would use the "author" field? Just send an object {"whiteboard":"drawLine(x,y,z)"} instead of {"author":"SVR_CMD","contents":"drawLine(x,y,z)"}.
But it is right, eval() is still an invitation for hackers. One can always send invalid data and try to influence the output more or less directly. The only way for escaping is a proper serialisation of the data you want to receive and send - the drawings data. How do you receive the whiteboard commands? There is no serverside "escape" function to make javascript code "clean" - it would always be a security hole.
I would expect a serialisation like
message = {
"author": "...", // carry the information /who/ draws
"whiteboard": {
"drawline": [200, 345, 222, 333]
}
}
so you can sanitize the commands (here: "drawline") easiliy.
The use of eval() might be OK if you have very complex commands and want to reduce the transferred data by building them serverside. Still, you need to parse and escape the received commands from other clients properly. But I'd recommend to find a solution without eval.
Setting eval issue aside, do not use field that can be filled by user - .author in your code - for authentication purposes. Add another field to your JSON message, say .is_server_command that when present, would signify special treating of message. This field is will be not depended on user input and thus wouldn't be hijacked by "hacker".