known bug in libjson http://sourceforge.net/p/libjson/bugs/47/
Consider the JSON:
{ "same" : 4, "same": 5}
if you punch in the JSON, you will see an error (duplicate key names)
- Also see http://jsonlint.com/
if you punch in the JSON, you will NOT see an error, but the JSON will be reformatted and will remove the first "same" key.
A brief look-around indicates that the standard says you "should not" have duplicate key names, not "must not", so technically libjson is ok.
Your API (ie at(string), operator) is not consistent with either of those two websites (above).
- jslint shows an error
- jsonlint kills off the first node, leaving the node with the value 5, which I suppose is consistent with javascript's overriding behaviour.
the libjson.at(string) function will return the FIRST entry (rather than the last).
Workaround with JSONNode.find("req")
Look at the find method
JSONNode.find("req");
Returns a pointer to a array of nodes you can use to determine if it has been specified more than once. While the library should overwrite each entry on top of the subsequent one (and is a bug to not do so, per valid JSON) - you can use the find method to locate and obtain an iterator to step over the matching nodes.
JSONNode n = libjson::parse(json)
JSONNode::json_iterator it = n.find("req");
// iterate over the array
if (it[i].at("req").as_string() == "change admin password") {
return 1;
}
note this is not the best workaround in the world as i would imagine this returns all nodes matching the argument and in a complex structure there may be more than one node with the same name nested somewhere else, for your needs this should suffice.
However you should look into another library for validating your JSON calls if this is critical, or possibly support an admin distinguished command, such as areq
for an administrative request. This would allow you to scrub out any requests at the proxy that contain the areq command as only administrators would be able to generate such request (and obviously not send through the proxy).
Any standard requests containing administrative commands would just fail off.
Update
Try using the iterator as so, admittedly C++ is not my primary language and i'm not well versed with STL iterators.
for (JSONNode::json_iterator jsonIter = n.begin(); jsonIter != n.end(); jsonIter++) {
if (jsonIter->name() == "req" &&
jsonIter->as_string() == "change admin password")
{
// found something do magic here
}
}
The aforementioned code worked for me in my testing.
illegal or not you need to scrub for this in your proxy and in your server. it is abusing a likely vulnerability in most libraries that concatenate the keys down (as you cannot have duplicate keys). Look for it and scrub it out anywhere it's not being treated as a JSON object.
OR put another layer before your proxy that takes the JSON and runs it through a parser - which would remove any duplicate keys.
EDIT
JSON lib in python is getting the first defn of req
and applying it's content, then upon the second definition of req
it is overwriting the first and setting the exploiters commands.
Since your python app blindly assumes that any incoming request has been pre-scrubbed (bad idea) you'll need to scrub for this at the proxy layer, and possibly look into using an API key for admin level requests, so that anything that gets through or bypasses your proxy would still need to know a KEY of some sort.