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

Christian Studer picture Christian Studer · May 5, 2010 · Viewed 28.4k times · Source

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.

Answer

Brett Wejrowski picture Brett Wejrowski · Jun 5, 2012

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