Abstract:
The method writes unvalidated input into JSON. This call could allow an attacker to inject arbitrary elements or attributes into the JSON entity.
Explanation:
JSON injection occurs when:
1. Data enters a program from an untrusted source.
2. The data is written to a JSON stream.
Applications typically use JSON to store data or send messages. When used to store data, JSON is often treated like cached data and may potentially contain sensitive information. When used to send messages, JSON is often used in conjunction with a RESTful service and can be used to transmit sensitive information such as authentication credentials.
The semantics of JSON documents and messages can be altered if an application constructs JSON from unvalidated input. In a relatively benign case, an attacker may be able to insert extraneous elements that cause an application to throw an exception while parsing a JSON document or request. In a more serious case, such as ones that involves JSON injection, an attacker may be able to insert extraneous elements that allow for the predictable manipulation of business critical values within a JSON document or request. In some cases, JSON injection can lead to cross-site scripting or dynamic code evaluation.
Example 1: The following JavaScript code uses jQuery to parse JSON where a value comes from a URL:
var str = document.URL;
var url_check = str.indexOf('name=');
var name = null;
if (url_check > -1) {
name = decodeURIComponent(str.substring((url_check+5), str.length));
}
$(document).ready(function(){
if (name !== null){
var obj = jQuery.parseJSON('{"role": "user", "name" : "' + name + '"}');
...
}
...
});
Here the untrusted data in name will not be validated to escape JSON-related special characters. This allows a user to arbitrarily insert JSON keys, possibly changing the structure of the serialized JSON. In this example, if the non-privileged user mallory were to append ","role":"admin to the name parameter in the URL, the JSON would become:
{
"role":"user",
"username":"mallory",
"role":"admin"
}
This is parsed by jQuery.parseJSON() and set to a plain object, meaning that obj.role would now return "admin" instead of "user"
Recommendations:
When writing user supplied data to JSON, follow these guidelines:
1. Do not create JSON attributes with names that are derived from user input.
2. Ensure that all serialization to JSON is performed using a safe serialization function that delimits untrusted data within single or double quotes and escapes any special characters.
Example 2: The following JavaScript code implements the same functionality as that in Example 1, but instead verifies the name against a whitelist, and rejects the value otherwise setting the name to "guest" prior to parsing the JSON:
var str = document.URL;
var url_check = str.indexOf('name=');
var name = null;
if (url_check > -1) {
name = decodeURIComponent(str.substring((url_check+5), str.length));
}
function getName(name){
var regexp = /^[A-z0-9]+$/;
var matches = name.match(regexp);
if (matches == null){
return "guest";
} else {
return name;
}
}
$(document).ready(function(){
if (name !== null){
var obj = jQuery.parseJSON('{"role": "user", "name" : "' + getName(name) + '"}');
...
}
...
});
Although in this case it is ok to perform whitelisting in this way, as we want the user to control the name, in other cases it is best to use values that are not user-controlled at all.
0 comments:
Post a Comment