Is there any risk of not validating the name of a function used in JSONP?

Asked

Viewed 103 times

2

Generally, when a service is available JSONP one of the things to be passed by parameter is the name of the callback that will be used in javascript.

Example:

$dados = [1, 2, 3];

$json = json_encode($dados);

$callback = $_GET['callback'];

printf('%s(%s)', $callback, $json);

Requisition:

jsonp.php?callback=my_function

Upshot:

my_function([1, 2, 3]);

However, my concern is whether the value passed as callback is a value of a valid javascript function.

That’s really something I should be worried about?

  • But the goal of JSONP does not return the name of a pre-defined function on the requesting page ?

2 answers

6


Absolutely! Although those who are at greatest risk are the page that uses your service (after all you could inject malicious code into it), there are attacks that take advantage of the fact that the server does not sanitize its entries. wikipedia list some of them. Let me give just one example, which should be enough to realize the importance of validating what your server sends to the user.

Reflected File Download

The idea behind of that attack is to explore websites that reflect back arbitrary content sent to them. The browser, seeing malicious content arrive from the legitimate site, acts on that content without question. It is an example of confused Deputy Attack.

In the case of JSONP what an attacker can do is limited, but I found an example that uses that protocol. I will try to summarize it here (there is no way to anonymize it - since the article is publicly available and easily retrievable - but I will avoid quoting the real service here because I am not sure whether this vulnerability has been fixed or not):

  • Your website has a JSONP API for any information:

    http://example.com/api/jsonp?callback=myCallback
    
  • It does not validate the function name, allowing to execute arbitrary code:

    http://example.com/api/jsonp?callback=alert%28document.cookie%29%3Bfoo{}
    

    Executes in the browser user’s:

    alert(document.cookie);
    foo{}( resposta do jsonp );
    

    Okay, the user’s cookies have been accessed, but so far who’s in trouble is just the site that made the request, not yours...

  • HTML5 has an attribute for the element a - download - which causes when the user click on the link instead of the browser take you to a page, a download is started. Second the documentation it even supports Uris of the type blob: and data:! (Note: I don’t know the implications of this on safety, and in any case it’s not relevant to this case)

    Suppose such a link is created pointing to your website’s JSONP API:

    <a href="http://example.com/api/jsonp?callback=algo_malicioso" download="instalador.exe">Link legal!</a>
    

    If your site cheerfully reflects that content back, a download will be started on browser user, reported as coming from your website, but the contents of it were partially provided by the attacker (who can find a way to ignore what you posted back, according to the specific syntax of the file he wants to return).

All the attacker needs to do then is convince some people (in a process of phishing for example) accessing this link and opening the returned file. Note that even the most attentive users will look at the URL and find that in fact it is a pro link your website... And the browser you will also consider this when applying your download security policies.

Okay, validate is accurate, but how?

As Marco Aurelio has already commented on your answer, the more validation you do the more restricted will be the way to use your service (the client wants objetoGlobal.array[42].objeto.metodo, but you only accept callbacks simple, it is obliged to create a new global function). However, this shouldn’t be a big problem - just define the new global function, with a random and unique name, and remove it at the end of the run. A simple validation like the regex suggested seems to me good size.

You could also "violate JSONP rules" in order to make it more difficult to exploit vulnerabilities of this type. Instead of returning:

callback({ ... });

you could return:

;(function() { callback({ ... }); })();

and the result should be the same (and it becomes more difficult - but not impossible - to act on a content that is in the middle of an expression, not at its beginning). I’m not saying it’s necessarily a good idea, just raising a possibility...

After all, the ideal is to avoid JSONP whenever possible. Have you considered the possibility of using CORS? Allowing arbitrary domains to access your server is always a risk, and you would have to plan accordingly (e.g., not rely solely on cookies to determine whether or not a user is logged in), but at least in that case you would only be dealing with dice, which are much simpler to manage than code, besides not being tied to echoing back something received from the customer.

  • 1

    I changed the "solved" because I think that answer has more details :)

  • 3

    Thanks! It’s good that more people will be aware of this possibility. Until recently I also agreed with the other answer, but security is the same: every change in technology also changes our assumptions, and what was previously safe suddenly ceases to be.

4

You can validate the call function, but this will restrict the use of your service.

An attack could occur as a way to inject code into some page, where the javascript return code(jsonp) would be executed. But the code on that page would already be compromised by letting anything run. The problem would be on the page and not on the service.

You could restrict the use to just names. Something like this regular Expression:

^[A-Za-z_][A-Za-z0-9_]*$ 

read: name must start with a lower or upper case text character, or an underscore, followed by multiple text characters or numbers or underscore.

I believe that other characters could be added without much trouble, like the point, for example.

But big security problem lies in the application that is using your service, by allowing code injection on the page or being a malicious page. Even if you contact your service, there may be others available for the attack. Or the attacked page may have more code with Wrappers in valid function form.

If the problem is data security, maybe you can add access control to the service and encryption.

  • Although you have accepted this answer, please take a look at mine; there is yes a very real risk in not validating the user input and echoing back to the customer. Anyway, a validation as suggested here seems to me a good idea.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.