David said:
Don't believe most of what you read. Never use eval unless
its use is appropriate. Evaluating JSON data is an
appropriate use. Just don't do it if the data comes from
somebody else's server.
<snip>
That is a bit of an over simplification. While it would be a bad idea
to - eval - anything originating on someone else's server (or even
import a JS resource from someone else's sever in a SCRIPT element (at
least without the sort of absolute trust in that third party that is
difficult to justify)) it is not necessarily a good idea to just trust
anything originating on your own servers. Specifically, if a JSON
response was incautiously built on the server such that it took some
character sequence from some location (database or the like) and just
inserted it into a data context in a JSON response prior to broadcasting
it (i.e. just placed the character sequence between the quote marks of a
piece of string data in the JSON response), then there is a potential
script insertion vulnerability. This may be the case with a JSON
response that reflected back data that a user has input, or in
circumstances where a disgruntled/dishonest employee had the ability to
alter the contents of the database.
In reality it is only safe to - eval - a JSON response (even from your
own server) into an object structure on the client if you know either
that the JSON is guaranteed to have a particular predefined
form/structure and/or that any data inserted into it is/has been
properly escaped for the JSON data context, so that there is no chance
that any of its contents will be treated as executable source code. This
is best guaranteed by knowing that the software that builds the JSON
response always (and unconditionally) carries out a proper escaping
process at the point of building the response. Inevitably that means an
overhead for the server in building the responses (as most actual data
will probably not need any active modification at that point).
An illustration (in order to make sure that any future reader of this is
in no doubt about what I am talking about):-
Suppose a client is expecting a JSON response along the lines of:-
[
{
"quanity":5,
"name":"Widget",
"unitPrice":"12.25",
"description":"something about what a Widget is"
},
{
"quanity":2,
"name":"Widget2",
"unitPrice":"5.14",
"description":"something about what a Widget2 is"
}
]
- it can - eval - that into a structure of objects. The database
contains a 'description' field that is inserted into the JSON response
as it is being built. The expected contents of such a field might be the
character sequence:-
Something about what a Widget is
- but suppose what the database actually contained was the character
sequence (assume no line breaks):-
Something about what a Widget is","evil"
function(){/*code that adds an
arbitrary SCRIPT element into the DOM and so imports a JS resource from
a (dubious) third party server */})(),"evil2":"
- If this were inserted between the quotes of the 'description' string
the first quote in the data would terminate the description string, the
next section of the character sequence would add an 'evil' property to
the object structure and than define the inline execution of a function
expression to provide the value for that property, and the rest of the
characters add an 'evil2' property with an empty string value (that last
property is to take account of the final quote mark that was originally
intended to terminate the 'description' string. Now the JSON structure
being imported is the equivalent of:-
[
{
"quanity":5,
"name":"Widget",
"unitPrice":"12.25",
"description":"Something about what a Widget is",
"evil"
function(){
/*code that adds an arbitrary SCRIPT element into the DOM
and so imports a JS resource from a (dubious) third party
server */
})(),
"evil2":""
},
{
"quanity":2,
"name":"Widget2",
"unitPrice":"5.14",
"description":"Something about what a Widget2 is"
}
]
- and if you - eval - it your client's browser will import a third party
script that can do anything at all (including (but far from limited to)
monitoring and broadcasting every user key press).
Now that 'description' field's contents came from somewhere. It may have
been entered by a dishonest employee, or it may have been entered by a
remote 'user' of some sort, but either way it should not have been
trusted to be 'safe'.
Escaping a sequence of characters for use in a JSON string context
involves going through the string and replacing some characters with
escape sequences (placing a backslash before them or replacing them with
Hex or Unicode escape sequences). If that is done during the process of
building the JSON response the outcome might resemble:-
[
{
"quanity":5,
"name":"Widget",
"unitPrice":"12.25",
"description":"Something about what a Widget
is\u0022,\u0022evil\u0022
function(){/* ...
*/})(),\u0022evil2\u0022:\u0022"
},
{
"quanity":2,
"name":"Widget2",
"unitPrice":"5.14",
"description":"Something about what a Widget2 is"
}
]
- and - eval -ing that will not have any side effects as that
'description' string is once again just a sequence of characters.
(So the next script insertion issue is with what the client-side script
does with the 'description' field, but that has nothing to do with
whether it is 'safe' to - eval - a JSON response.)
Richard.