I'm writing an Angular2 web application, and I want bidirectional communication with the server, so the perfect solution is with websockets.
Mozilla fundation teaches to use JSON.stringify(msg) to parse a string that represents a JSON message, both for sending and receiving data with websocket. This leads to some thoughts on injection. For example, suppose the following JSON document being transfered from the server to the client's machine:
{
message{
from: "paul",
text:"hello!",
date:"01/01/2017"
}
}
Now suppose paul changes his name to "paul\" and sends the following text:
,text: alert('xss'),something:"
then the following JSON received by the client would be:
{
message{
from: "paul\",
text:",text: alert('xss'),something:"",
date:"01/01/2017"
}
}
which is, in fact, the following JSON (just rearranged):
{
message{
from: "paul\",text:",
text: alert('xss'),
something:"",
date:"01/01/2017"
}
}
which could cause problems, depending on what is done with this JSON, I guess. Is there some way to prevent these things, or is the JSON.stringfy technique safe because when inserting data from the JSON into the DOM, the text attribute would be undefined because alert('xss') is not a string (or does not return anything)?
Also, see that if there's no problem with calling a function like alert(), we were able to set the something variable to anything we wanted, this is for sure risky.
Related
Description of the problem
I will not write any codes as much of my problem is something linked with the knowledge to interpret some data. I am doing a project and had to use a nonsql database to store data the sampled information from a microcontroller. The chosen db was mondodb. I wrote all the code that stores the info and now i want to exhibit the date on a html page. The problem is that when i do the request using restapi to the mongodb, the json that was stored there comes in the extened json format, i.e.:
"_id": {
"$oid": "6230d05dcf81542c5aabc30b"
},
"sensor": {
"$numberDouble": "1"
}
But it should have come as the data is stored in the db:
"{
_id": "6230d05dcf81542c5aabc30b",
"sensor": 1.0
}
As you can see, the the json comes with extra information linked to the type of the variable that is stored. But i don't really know how to use that information in javascript. I would just read it for example as json.sensor.$numberDouble if i wanted to get the information about the sensor instead of json.sensor if the json was in the normal way. I don't see much of an use to the extended version. Is something i am doing wrong?
Make sure, that you Parse API response, like-
response.json()
It looks like you're getting back an EJSON response. If you want to send back standard JSON response then that should be set as the Content-Type on the server response.
function(req, res) {
data = { ... }; // Your data here
res.setHeader("Content-Type", "application/json");
res.setBody(JSON.stringify(data));
}
If you don't have control over the server side, then convert the EJSON back to plain JSON using the meteor EJSON library.
I am trying to prevent JavaScript injections via JSON in a JObject like so:
public class JsonService : IJsonService
{
private JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings()
{
StringEscapeHandling = StringEscapeHandling.EscapeHtml
};
public JObject SanitizeJson(JObject jsonToSanitize) {
string sanitizedJsonString = JsonConvert.SerializeObject(jsonToSanitize, _jsonSerializerSettings);
JObject sanitizedJson = JObject.Parse(sanitizedJsonString);
return sanitizedJson;
}
This is all good fun, until I realize that my input looks like this:
{
"submission": {
"firstName": "<script>document.write('script kiddie');</script>",
"birthday": "05/21/2015",
"submit": []
}
}
My "sanitizedJsonString" looks like this:
"{\"submission\":{\"firstName\":\"\u003cscript\u003edocument.write(\u0027script
kiddie\u0027);\u003c/script\u003e\",\"birthday\":\"05/21/2015\",\"submit\":[]}}"
And my "sanitizedJson" looks like this:
{{
"submission": {
"firstName": "<script>document.write('script kiddie');</script>",
"birthday": "05/21/2015",
"submit": []
}
}}
Note that while the formatting into a string does escape the javascript, it's right back in the code the moment I turn it back into a JObject. In other words, a script gets saved to the database. My end goal is not to have form submissions (that come through as JSON I don't control) get saved in the db. I DO need to serialize the string back into a JObject on trip back to client, so I need it cleaned from the JObject. I am tempted to do str.Replace("<",""), etc, but that's obviously not a real solution.
How do I accomplish cleaning out the <script> tags?
Additions from comments:
I am getting JSON from third-party front-end.
I am sending back JSON to third-party front-end, some of which will be rendered as html.
Edit 2:
Tried AntiXSS via NuGet, it is not compatible with .NET Core: https://www.owasp.org/index.php/.NET_AntiXSS_Library
I think the best option is to reject the input JSON when you see any suspicious characters in it. But when that is not possible, we can at least validate it for XSS attack.
I was in the same boat & I found a pointer in another question here: AntiXSS in ASP.Net Core
Hope you can carve out your solution from this reference as well.
Initially the content from the server was JSON data.And I was able to access the data perfectly.
{ "status":"ok", "artifact":"weblayer-war", "version":"0.0.41-test-data", "buildtime":"test-data" }
Now the response from the server has been changed to json data + text data.
{ "status":"ok", "artifact":"weblayer-war", "version":"0.0.41-test-data", "buildtime":"test-data" }
Properties for service:
=======================
ServiceEndpoint: https://somedomain:1200/web/Servlet/SOAP/Services
Certificates: false
DocumentName: note.pdf
So whether changing the content-type to application-text and using split method is the only way we can solve this or Is there any better approach?
As mentioned in the comments, mixing JSON and pure text data is wrong (as it defeats the advantage of using standardized data format) and should be avoided. Maybe that is some kind of debug log that was accidentally included in the production code?
If not, you should read just the first line of response and parse it as JSON data, ignoring the rest, hoping for no more changes in response structure ;)
You really should overthink your API design.
What about adding the text part as part of your JSON?
{
... // your JSON properties here
"serviceProperties": { // properties for service
"ServiceEndpoint": "https://somedomain:1200/web/Servlet/SOAP/Services",
"Certificates": false,
"DocumentName": "note.pdf"
}
}
I am making a mobile app with Phonegap and using Wordpress as a backend. I am using Advanced Custom Fields with a Google Maps post field which returns a PHP object to the app using JSON API. My Wordpress backend sends a normal JSON object to the app, but inside that object is where a stringified PHP object is returned.
I need to convert the PHP object to a JSON object somehow on the client side(the app which is not in Wordpress). I have looked at other answers that say to use json_encode for this but my problem is that the app is just HTML/Javascript and no PHP. Is there a way to use PHP code in the middle of a Javascript function to do this? Or would it be better to change the backend so that it returns a JSON object instead of a PHP object in the first place? If so, how do I do that?
My experience in PHP is still somewhat limited so any help is appreciated.
edit: To clarify a bit more, I am using Wordpress on a separate domain from my Phonegap app and only using the JSON API plugin on the Wordpress end. I am then using jQuery Ajax calls to retrieve data from the Wordpress backend.
Also the returned PHP object looks like this: a:3:{s:7:\"address\";s:48:\"8915 W 159th St, Orland Hills, IL, United States\";s:3:\"lat\";s:17:\"41.60111599999999\";s:3:\"lng\";s:11:\"-87.8364575\";}
Another way I just thought of as well, would it be possible to just leave it as a PHP object and still read out the values from it somehow? I don't NEED it to be a JSON array, I just need a way to read the individual elements in the array in one way or another.
Here is also a tiny snippet of the JSON returned to clarify what I'm talking about.
"custom_fields": {
"location": [
"a:3:{s:7:\"address\";s:48:\"8915 W 159th St, Orland Hills, IL, United States\";s:3:\"lat\";s:17:\"41.60111599999999\";s:3:\"lng\";s:11:\"-87.8364575\";}"
]
}
That of course isn't the entire JSON object but it gives you an idea of what I'm dealing with.
I know you have a solution that works on the front end, but I still think it'd be better to fix this on the server.
Based on our conversation in the comments, I've had a closer look the code in the WordPress forum. The problem seems to be that the location field is an array of strings, not just a string. maybe_unserialize (and is_serialized, which it uses) don't handle arrays. Here's the updated code, which you should be able to drop into your theme's functions.php. I did a quick test, and it works for me.
class unserialize_php_arrays_before_sending_json {
function __construct() {
add_action( 'json_api_import_wp_post',
array( $this, 'json_api_import_wp_post' ),
10,
2 );
}
function json_api_import_wp_post( $JSON_API_Post, $wp_post ) {
foreach ( $JSON_API_Post->custom_fields as $key => $custom_field ) {
if (is_array($custom_field)) {
$unserialized_array = array();
foreach($custom_field as $field_key => $field_value) {
$unserialized_array[$field_key] = maybe_unserialize( $field_value );
}
$JSON_API_Post->custom_fields->$key = $unserialized_array;
}
else {
$JSON_API_Post->custom_fields->$key = maybe_unserialize( $custom_field );
}
}
}
}
new unserialize_php_arrays_before_sending_json();
If you're using a JSON API to retrieve the data, then why don't you deliver the data in JSON format to your app? Otherwise you seem to remove much of the point of using an API in the first place... You could of course parse that string in JavaScript if you really want to but that's a very ugly and error prone solution.
The JSON API plugin does seem to use JSON:
https://wordpress.org/plugins/json-api/screenshots/
I need to convert the PHP object to a JSON object somehow on the client side(the app which is not in Wordpress).
This bit here leaves me confused. You do not have PHP objects on the client-side, PHP is a back-end technology. What is returned to the client is a string which can be HTML, XML, JSON, plaintext on any other form of encoding.
That said, saying you have an object $obj in PHP, you could pass it to your front-end application creating an end-point retrieve_object.php and in there:
echo json_encode($obj);
So long as that is the only thing your are outputting, you lient-side app can make a request (Eg: AJAX) to retrieve_object.php and get the json object.
BUT , and this is important (!) in doing so you serialize object properties. You will lose any PHP object method. If any object property is an object itself (EG: A DB Connection) then this will be lost too.
Hope this helps!
I've used the webOS Ares tool to create a relatively simple App. It displays an image and underneath the image are two labels. One is static, and the other label should be updated with new information by tapping the image.
When I tap the image, I wish to obtain a JSON object via a URL (http://jonathanstark.com/card/api/latest). The typcial JSON that is returned looks like this:
{"balance":{"amount":"0","amount_formatted":"$0.00","balance_id":"28087","created_at":"2011-08-09T12:17:02-0700","message":"My balance is $0.00 as of Aug 9th at 3:17pm EDT (America\/New_York)"}}
I want to parse the JSON's "amount_formatted" field and assign the result to the dynamic label (called cardBalance in main-chrome.js). I know that the JSON should return a single object, per the API.
If that goes well, I will create an additional label and convert/assign the "created_at" field to an additional label, but I want to walk before I run.
I'm having some trouble using AJAX to get the JSON, parse the JSON, and assign a string to one of the labels.
After I get this working, I plan to see if I can load this result on the application's load instead of first requiring the user to tap.
So far, this is my code in the main-assistant.js file. jCard is the image.
Code:
function MainAssistant(argFromPusher) {}
MainAssistant.prototype = {
setup: function() {
Ares.setupSceneAssistant(this);
},
cleanup: function() {
Ares.cleanupSceneAssistant(this);
},
giveCoffeeTap: function(inSender, event) {
window.location = "http://jonathanstark.com/card/#give-a-coffee";
},
jcardImageTap: function(inSender, event) {
//get "amount_formatted" in JSON from http://jonathanstark.com/card/api/latest
//and assign it to the "updatedBalance" label.
// I need to use Ajax.Request here.
Mojo.Log.info("Requesting latest card balance from Jonathan's Card");
var balanceRequest = new Ajax.Request("http://jonathanstark.com/card/api/latest", {
method: 'get',
evalJSON: 'false',
onSuccess: this.balanceRequestSuccess.bind(this),
onFailure: this.balanceRequestFailure.bind(this)
});
//After I can get the balance working, also get "created_at", parse it, and reformat it in the local time prefs.
},
//Test
balanceRequestSuccess: function(balanceResponse) {
//Chrome says that the page is returning X-JSON.
balanceJSON = balanceResponse.headerJSON;
var balanceAmtFromWeb = balanceJSON.getElementsByTagName("amount_formatted");
Mojo.Log.info(balanceAmtFromWeb[0]);
//The label I wish to update is named "updatedBalance" in main-chrome.js
updatedBalance.label = balanceAmtFromWeb[0];
},
balanceRequestFailure: function(balanceResponse) {
Mojo.Log.info("Failed to get the card balance: " + balanceResponse.getAllHeaders());
Mojo.Log.info(balanceResponse.responseText);
Mojo.Controller.errorDialog("Failed to load the latest card balance.");
},
//End test
btnGiveCoffeeTap: function(inSender, event) {
window.location = "http://jonathanstark.com/card/#give-a-coffee";
}
};
Here is a screenshot of the application running in the Chrome browser:
In the browser, I get some additional errors that weren't present in the Ares log viewer:
XMLHttpRequest cannot load http://jonathanstark.com/card/api/latest. Origin https://ares.palm.com is not allowed by Access-Control-Allow-Origin.
and
Refused to get unsafe header "X-JSON"
Any assistance is appreciated.
Ajax is the right tool for the job. Since webOS comes packaged with the Prototype library, try using it's Ajax.Request function to do the job. To see some examples of it, you can check out the source code to a webOS app I wrote, Plogger, that accesses Blogger on webOS using Ajax calls. In particular, the source for my post-list-assistant is probably the cleanest to look at to get the idea.
Ajax is pretty much the way you want to get data, even if it sometimes feels like overkill, since it's one of the few ways you can get asynchronous behavior in JavaScript. Otherwise you'd end up with code that hangs the interface while waiting on a response from a server (JavaScript is single threaded).