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

Yes, you need to sanitize the callback parameter.

JSONP is basically a self-inflicted XSS attack. When (temporarily) inserting of script tag with a url to a different hostname and letting it call a global function or method on your page, it is important to at least take some precautions that you limit "callback" to be nothing more but a callback name.

A callback name should, syntactically, be as simple as an identifier. You could make an allowance for object properties. I would recommend against allowing parentheses, since that might enable function invocations, etc.

Below is an example of a basic API that supports both JSON and JSONP. It is written in PHP (simplified from MediaWiki's API), but similar structures can be created in other programming languages.

<?php

// Simulate the response data
$responseData = [
    'foo' => 'bar',
    'count' => ['one', 'two', 'three'],
    'total' => 3,
];

// Prepare to send the response
$prefix = '';
$suffix = '';
$ctype = 'application/json';

if (isset($_GET['callback'])) {
    $ctype = 'text/javascript';
    // Sanitize callback
    $callback = preg_replace("/[^][.\\'\\\"_A-Za-z0-9]/", '', $_GET['callback']);

    $prefix = $callback . '(';
    $suffix = ')';
}

// Send the response
header("Content-Type: $ctype; charset=UTF-8", true);
print $prefix . json_encode($responseData) . $suffix;
exit;

Yes.

As described by @YOU an attacker could craft a callback parameter that evaluates to malicious javascript, or worse, malicious Flash.

Validating that the callback isn't a reserved word and is alpha-numeric as described by @Brett-Wejrowski is a good start.

Google, Facebook and Github are mitigating the Rosetta Flash vulnerability by pre-pending an empty comment, like /**/, to the jsonp callback.

Another approach would be to return a safer javascript expression like ExpressJS does:

typeof callbackstring === 'function' && callbackstring(.....);

Yes, when callback is like

(function xss(x){evil()})

When you echo back from php, will looks like

(function xss(x){evil()})(json)

function xss will run and evil() can be some codes sending cookies to somewhere else.

So, sanitize it to only valid function names, for example, limit it to alphanumeric


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

Tags:

Jsonp

Xss