Nginx JSON hacks
gabrielweinberg.com
gabrielweinberg.com
API keys usually exist for preventing abuse. By exposing an authenticated API proxy you're allowing anyone to abuse someone else's API using your key, likely leading to them banning you. At a minimum you should implement your own rate limiting.
Likewise, with a JSONP proxy you're allowing other sites to circumvent the browsers' same origin policy to access that API, which could also lead to abuse. At a minimum you should restrict requests to ones with a recognized HTTP Referer header.
Of course with JSONP you also need to trust that the API isn't doing anything malicious, like injecting cookie or other data-stealing JavaScript instead of valid JSON. It would be a good idea to validate that the response is indeed JSON before passing it back to the clients (actually a properly restricted sanitizing JSONP proxy would be a good idea even if the API already provides JSONP)
So use these techniques cautiously...
The article describes how to set up caching in nginx, so not every request to nginx goes to the external service.
For instance, we're doing this proxying with Tumblr (sans API key, fortunately) and they occasionally issue a 302 redirect and tack on some parameters. (for caching reasons, I assume) The 'Location' header that is sent back would have your API key in it, so you'd need to detect that and strip it out. Also, if they throw a 500 error they may echo your URL back at you.
I'd probably move this code up into this application layer unless you're very sure about the API you're using.
Then there is rate limiting etc, depends on the service.
location ^~ /ext_api3/ {
echo_before_body $arg_callback //+somehow add "(";
proxy_pass http://api.external.com/;
echo_after_body ');';
}Now all an attacker needs to do is get one of your users with an active session to load a page that does <script src="usersprivatedata.jsonp"></script> and they can gather that data.
<?php
//inject json
//this puts the json in a div
//then the js gets the div's innerText and parses it as JSON
//so there's an object in js (global) with all the JSON data, with jsonInject's key name
if(isset($jsonInject) && count($jsonInject) > 0){
foreach($jsonInject as $i=>$json){
echo "<div style='display:none;' id='jsonInject_{$i}'>{$json}</div>"
echo "<script>var {$i} = JSON.parse( $('#jsonInject_{$i}')[0].innerText ); </script>";
}
}
?>
fill the associative $jsonInject array with json strings in your controller. then this goes in your templater. it makes a hidden div, puts the json string in there. then jquery pulls the innerText value, it gets parsed as json and stored in a js var. depending on use, i'll sometimes just pass the results of JSON.parse to an initialize method.I like the proxy caching. I think apache's mod_proxy and mod_cache could do this but with more config (and resources per request).
That's assuming the API is using HTTP cookies for authentication, right? If it's not then theres no way for a 3rd party to construct an authenticated request without knowing the credentials.
The real problem here is that a JSONP proxy allows 3rd party sites to access the API from your IP address (and API key if you use the suggestion of an API key proxy). Rate limiting and restricting to specific HTTP Referrers would be prudent.
(I have nothing against node, mind you. I've used it for something similar to Google Wave, and it was very straightforward and capable.)