Safely pass object to client in Node.js/express - javascript

A common question is how to pass an object from Node.js/Express.js to the browser. It's possible to do that using JSON stringify, but if the object contains user-provided data, that can open the door to script-injection and possibly other attacks.
Is there a downside to the approach mentioned in this link using Base64?
https://stackoverflow.com/a/37920555/645715
Related links:
Passing an object to client in node/express + ejs?
How to pass a javascript object that contains strings with quotes from node.js to the browser?
Pass a NodeJS express object to AngularJS 1.6
Passing an object to client in node/express + ejs?

Using Base64 encoding does solve the immediate problem of passing back an injection attack, but it doesn't necessarily solve the issue of having a possible injection attack floating around out there. For example, this fiddle shows that it does prevent the immediate issue : https://jsfiddle.net/9prhkx74/
var test2 = JSON.parse(window.atob('PC9zY3JpcHQ+PHNjcmlwdD5hbGVydCgndGVzdDInKTwvc2NyaXB0PjxzY3JpcHQ+'));
This won't show an alert box, it'll just throw an error about invalid JSON. But if you change it to the literal string, it'll show the alert box (injection vulnerable)
var test2 = JSON.parse("</script><script>alert('test2')</script><script>")
Now if you are immediately parsing it to a JSON object, it'll blow up, and everything will be "safe". But if you assign it to a value because you are going to pass it around some more etc, you still have a potential issue out there.
Instead of putting a bandaid on the injection itself, I'd suggest fixing it in the first place and properly escaping data before passing it back to the client or processing it on the server side.
There are plenty of libraries that can help do this
https://www.npmjs.com/package/sanitize
https://www.npmjs.com/package/express-sanitizer
Here's a pretty good article that kind of highlights why it is important to sanitize and not just just patch over potentially malicious data : https://lockmedown.com/5-steps-handling-untrusted-node-js-data/

Related

Check if a string contains executable code in JavaScript?

I have an Android app that runs my code(which is a JS bundle) in a hidden webview. I make API calls through native code using a JS interface. The response is sent back to a function through the evaluetJavascript method of the webview. The concern here is somehow a malicious response is received which might execute arbitrary JS in my webview. I am base-64 encoding the result before calling the evaluateJavascript and once it reaches the JS, I just decode it and parse the JSON and then it's just a string value which gets used further.
I have 2 questions:
(1) Since I am not using eval() anywhere in my JS code, is my understanding correct that even if a code gets through, it won't ever execute?
(2) I have been asked to still validate the data. Is there any way to detect if a given string contains executable JS code? I thought of looking for characters like ;"'() etc. but have concerns that my data may contain parentheses and that a stringified JSON will have quotes anyways. I am worried about false positives. What will be a better approach for this?

How to export JavaScript object as JavaScript?

I'm looking for most elegant way of "dumping" simple JavaScript object into JavaScript source-code generated on-fly.
Purpose:
Assume we have node.js server generating HTML. We have an object x on server side. The object is simple - only strings/ints/arrays in it (so, it's JSON-able). I want to "embed" object x into HTML being generated, to be available for JavaScript code which will run on the browser. So the code:
console.log(x);
will dump exactly the same data on both server-side and browser-side.
For example - imagine I'm going to pass some additional config/data to JavaScript running on browser.
Obvious solutions:
Encoding as JSON and send as AJAX/Websocket is not a part of this question as we have to embed the object in the HTML. I don't want additional HTTP requests - everything should be passed in one go.
Encoding as JSON and simply attach to variable sounds initially good, but involves some additional escaping steps.
Using util.inspect() works for me, in this way:
var toHtml = 'var x = ' + util.inspect(theXonServer, {depth:9}) + ';';
but I'm not sure if it's "elegant" (and secure and error-prone and...)
Any better suggestions ? Standard way of doing that ?
The Wrong Way to Pass Data
It's common to get advice to just stringify some JSON and dump it into a <script> tag. This is bad advice. Don't do it.
It's important to understand why this is a bad idea.
When you string-build JavaScript, you're opening yourself up to all sorts of quirks of the language that you'd absolutely be required to understand to make sure that there are no issues.
One such quirk is that within a <script> element, the first occurrence of </script> will close the <script> element. It doesn't matter that it's in a string, the script will be closed, and the rest of the contents after that point will be treated as HTML.
HTML escaping doesn't work because JS doesn't like HTML entities.
what might start as:
<script>
window.xss = <%= JSON HERE %>
</script>
could turn into:
<script>
window.xss = {"username":"Robert Hackerman</script><script src='nefarious.js'></script>"}
</script>
Don't risk it.
The Right Way to Pass Data...
...When the Page is Rendering
The much safer way that prevents any script execution is via [data-*] attributes. You must HTML-escape the contents, but that's OK in attributes. I'm using a <script> element because it's implied that the script will be using the data.
What would start as:
<script data-foo="<%= HTML ENCODED JSON HERE %>" src="yourscript.js"></script>
Would turn into:
<script data-foo="{"username":"Robert Hackerman</script><script src=&apos;nefarious.js&apos;></script>"}" src="yourscript.js"></script>
And if you want access to that data, you can just access the attribute value, or use the dataset api (if your target browsers support it):
var fooElement = document.querySelector('[data-foo]');
var rawData = fooElement.dataset.foo;
// or
var rawData = fooElement.getAttribute('data-foo');
var data = JSON.parse(rawData);
console.log(data);
...After the Page has Rendered
If the page has already loaded, and you want to access some data, just use an AJAX request. You'll be able to safely read in a JSON data source, which can be piped through JSON.parse to access the data object.
Util.inspect vs JSON.stringify
You only need util.inspect if your object is circular. If it's JSON encodable in 99.9% of cases you can just output it to the source with JSON.stringify.
Using JSON
There are edge cases to this - not only are JS objects more expressive than JSON (functions etc), JSON objects can do things JS objects can't (in edge cases of encoding). So make sure not only is your object serializable correctly, it's also deserializable correctly. I also assume you didn't do anything crazy like override the array constructor (which would make JS objects behave differently from JSON ones).
Security
As for security, unless your object can contain sensitive data (and it really shouldn't, whitelist it first) there should not be any related issues.
Overall option 2 is a standard approach that is quite commonly used - including on this very site.
It usually works for simple data which is most data you need to share (numbers and strings).
It saves the round trip.
It's used very often in big sites and in practice.

Serialize object through network with Javascript - How to improve it?

I have a class Message which can be serialized when the data goes through the network, I currently use JSON, mostly because I use JSON for everything. (webservice, sockets).
I want to improve the serialization to make it as good as possible, I believe improvments are possible here.
The aim is to make the transport string lighter, especially when used by sockets (video game), because it will be used for everything, every response client/server or server/client and even inside the server or client methods, it's the usual way to provide data.
The Message is a complex object that can also contain other object instances, like a MessageLang, which will be responsable to translate a sentence on the client based on a code.
So far it works fine, here are the results:
Socket server emit with simple string:
verbose: websocket writing 5:::{"name":"user.newAuthenticated","args":["Respond to emitter"]}
Socket server emit with simple message instance:
verbose: websocket writing 5:::{"name":"user.newAuthenticated","args":["{\"m\":\"Respond to all clients\",\"d\":{},\"s\":1,\"t\":\"m\"}"]}
Socket server emit with complex message instance:
verbose: websocket writing 5:::{"name":"user.newAuthenticated","args":["{\"m\":{\"m\":\"__12\",\"a\":{\"field\":\"name\",\"min\":3,\"max\":20}},\"d\":{\"key\":\"fakeKey\"},\"s\":1,\"t\":\"m\"}"]}
The complexe message would render the following sentence:
The min length of name is 3. Max length is 20. and would contain the key: "fakeKey" in data. Just to explain how it works.
As you see, the message get bigger and bigger and it is normal, but I would like to know what I can do to make a better serialization here:
Delete the message itself when there aren't (empty)
Delete the data when it's empty as well
Delete the status when it's false (because it's the default value)
I see a lot of \ in the socket log because it is JSON, I believe that's a problem, because each time I'll add something I'll get extra characters that I do not want. Maybe the JSON isn't a good choice and I should serialize differently, first in JSON like the examples at the top, but then in something else, maybe kind of binary, if it takes less space.
What do you think?
And if it would be a good idea to encrypt somehow the message in another format, would the cost of the encryption be worth it? Because encrypt it would take a bit of time as well, so I'm just wondering if it wouldn't just move the issue, like it would take less time to send the message through socket because it would be lighter, but we would use more time to encrypt it. Just wondering.
My guess is that your message object has two fields (name and args).
The first stop to reduce the length of the message is to get rid of the (pretty useless) outer object and replace it with an array. So an empty message
{"name":"empty","args":[]}
would become
["empty",[]]
or even
["empty"]
The next thing is that you have a bug in the serialization of the arguments. Instead of sending JSON, you wrap the JSON data in a string. Example: In the authenticated case, you send
{"name":"user.newAuthenticated","args":["{\"m\":\"Respond to all clients\",\"d\":{},\"s\":1,\"t\":\"m\"}"]}
but you should send
{"name":"user.newAuthenticated","args":[{"m":"Respond to all clients","d":{},"s":1,"t":"m"}]}
instead. Now the question is whether args is a list of a single object. If it's always a single object, then you could get rid of the [] as well. With my suggested change from above, that would give you:
["user.newAuthenticated",{"m":"Respond to all clients","d":{},"s":1,"t":"m"}]
which is pretty good IMO. If you can make the (de-)serializer handle default values properly, you can reduce this to:
["user.newAuthenticated",{"m":"Respond to all clients","s":1,"t":"m"}]
(i.e. we can omit the empty d property).
For a MMO, I think a minimum of data must be sent to the client. If a socket is called 2xx/3xx by sec, you must reduce the size of the data sent through the socket as most as possible.
On another hand, it also consummes resource to encrypt the object on the server side to send a minified version of the object... Wouldn't it be better not to reduce it and to send an object not reduced so we don't spent resource to encrypt it?

Using Pylons global variables with JavaScript (escaping brackets)

I am trying to access a result in a dictionary held in a Python global variable within JavaScript.
var selected = jQuery('.target option:selected').text()
var list = "${c.persons_by_permission["+selected+"]}"
If I directly access the dictionary without the using the variable:
var list = "${c.persons_by_permission['stringID']}"
Then the code works.
However, when I am trying to use the variable to access the dictionary I get a syntax error (I believe its because of the curly braces).
I have tried escaping the braces with:
var list = "${{c.persons_by_permission["+selected+"]}}"
But it gives more syntax exceptions.
Any ideas?
EDIT:
This is not an issue of whether I can use Python and javascript together, it is more of a question of escaping the curly brackets
I am using pylons, so if I try:
alert("${c.persons_by_permission['Documents']}")
I will get the results I need. The issue is that I cannot find a way of passing a variable into the javascript in place of 'Documents'
I'm making a few (reasonable) assumptions hereā€¦
Your Python is running on your webserver
Your JavaScript is running on your client
As far as the Python is concerned it is outputting text. It doesn't care that the browser might interpret it as HTML, JavaScript or whatever. It just generates some text and then sends it to the browser.
With HTTP you get to make a request and have a response. You cannot stop a response half way through to get data back from the client.
You cannot pass data from client side JS back to the Python process that generated the JS. That process will have finished running.
You can either:
Send all the data to the client in the first place (and then select the bits you want in JS instead of in Python)
Have the JavaScript make a new HTTP request to the server and process the response in JS (this is known as Ajax and there are no shortage of tutorials out there for this)
I don't know what execution environment you are using,but I am almost certain that python and javascript are not executing at the same time.
${c.persons_by_permission['stringID']} looks to me like some kind of template directive. If so, this works because the directive is processed at template processing time. Your other form is just an expression in javascript that evaluates in javascript to a string.

How to show a friendly error message using Open-flash-charts2?

If my JSON data-file comes from a database result set and that result set is empty, how do I tell OFC2 to display an error message, instead of crashing because of a malformed JSON string?
Add tags for javascript and actionscript-3 to this question and you should get a load more views and useful responses than you currently are, with more precise details than I am giving. Post the actual JSON string that is causing you the problem and that you would like to be guarded against. That way people can suggest a regexp to catch it, treating it as a string rather than as JSON data at some point before JSON.decode() happens.
In more detail:
You can catch it in two places. One route is to switch over to using the javascript interface to OFC2 and use client side javascript to detect the bad string. This allows you to modify the JSON string client side. See http://teethgrinder.co.uk/open-flash-chart-2/tutorial-5.php for that approach. One downside is that the clients must have javascript enabled for this to work.
Alternatively, since OFC2 is LGPL, you or an actionscript developer can dive into the OFC2 source code and do the same thing there. I am not an actionscript developer so you are better off ensuring you get a reply from one.
The main thing is to add those two tags to this question. 22 Views is way too low for a question with a bounty of 500. Hope this helps.
Several solution avenues are possible, depending on your level of access to the server and your knowledge of JavaScript and/or any server-side platforms.
With access to database
Depending on the kind of data you are displaying, it might be possible to add dummy records for those queries that would otherwise have returned an empty set. If you have access to the query definition, you may check for the empty set in the DB-query. For example, if you're on MS SQL Server you could check the condition with some T-SQL statements.
With access to server
If you have access to the server side script generating the dataset, add a condition that returns some default value that OFC2 will handle correctly.
With access to another server or serverlocation
If you don't have access to the specific script, you may consider creating a new script at another location that queries the original script and replaces empty results with the default value.
Client-side only
You can add the JavaScript open_flash_chart_data function (see tutorial) to replace empty datasets. OFC2 can use that function as data source.
Hope this helps.

Categories