Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I need to sanitize the callback parameter from a JSONP call?

Tags:

jsonp

xss

I would like to offer a webservice via JSONP and was wondering, if I need to sanitize the value from the callback parameter.

My current server side script looks like this currently (More or less. Code is in PHP, but could be anything really.):

header("Content-type: application/json; charset=utf-8");
echo $_GET['callback'] . '(' . json_encode($data) . ')';

This is a classic XSS-vulnerability.

If I need to sanitize it, then how? I was unable to find enough information about what might be allowed callback strings. I quote from Wikipedia:

While the padding (prefix) is typically the name of a callback function that is defined within the execution context of the browser, it may also be a variable assignment, an if statement, or any other Javascript statement prefix.

like image 676
Christian Studer Avatar asked May 05 '10 21:05

Christian Studer


People also ask

What is JSONP callback?

By Arsal Khan. March 1, 2022. JSON with Padding, or JSONP for short, is a technique that allows developers to get around browsers' same-origin policies by exploiting the nature of the <script> element.

How JSONP works?

JSONP stands for JSON with Padding. Requesting a file from another domain can cause problems, due to cross-domain policy. Requesting an external script from another domain does not have this problem. JSONP uses this advantage, and request files using the script tag instead of the XMLHttpRequest object.

Does JSONP still work?

JSONP is still useful for older browser support, but given the security implications, unless you have no choice CORS is the better choice.


1 Answers

You want to ensure the callback is a valid identifier, which can be alphanumeric, underscore, or $. It also cannot be a reserved word (and just to be thorough I would make sure it is not undefined, NaN, or Infinity). This is the test I use:

function valid_js_identifier( $callback ){
    return !preg_match( '/[^0-9a-zA-Z\$_]|^(abstract|boolean|break|byte|case|catch|char|class|const|continue|debugger|default|delete|do|double|else|enum|export|extends|false|final|finally|float|for|function|goto|if|implements|import|in|instanceof|int|interface|long|native|new|null|package|private|protected|public|return|short|static|super|switch|synchronized|this|throw|throws|transient|true|try|typeof|var|volatile|void|while|with|NaN|Infinity|undefined)$/', $callback);
}

Many of the reserved words are pointless, but some of them could cause errors or infinite loops.

Important: do not just sanitize the input by replacing characters; the modified callback could run without error and the data returned will not be handled properly (or could even be handled by the wrong function). You want to test if the input is valid, and throw an error if it's not. This will avoid unexpected behavior and notify the developer that a different callback is needed.

note: This is a safer, but limited, version of JSONP that does not allow expressions or refinement. I've found it works great for most applications, especially if you are using jQuery and $.getJSON

like image 107
Brett Wejrowski Avatar answered Oct 18 '22 01:10

Brett Wejrowski