Ways to allows requests to APIs only from internal in PHP - php

I know CURL & HTTP authentication to allow API calls only from certain requests.
I have something like this
www.mysite.com/list
www.mysite.com/api
list page calls the api page using jQuery Ajax post request and api page echos jSON response.
I am already checking HTTP referrer to verify Post requests come from certain origins but these requests can be forged.
I cannot use $_SERVER['remote_addr'] as this will check the client ip not the source ip of the API request.
As both the pages are hosted in the same web server and in the same hostname, its not possible to restrict based on hostname or IP address.
I am aware of some alternatives like
cURL with HTTP Authentication.
Encryption of jSON response and Decrypting before printing.
But is there any way to restrict these API pages to securely block access from outside the server or hostname?

Assuming you want to restrict access to "Joe Random user who is visiting your website with a web browser".
Not really.
There's no way to reliably determine that the client is a regular web browser. Anyone writing some other client to access your API can easily have it visit your website and get whatever tokens they need to prove that.
The best you can do is some sort of heuristic approach that looks for unusual traffic patterns (such as unusually high numbers of similar requests from one source, or ones which have very stable intervals between requests). You'll get false positives and negatives from that kind of approach though.

I may be wrong, but I think you are trying to invent csrf tokens. But with little modification:
You should store generated token in session/cookie before rendering /list. I am not sure whether jQuery send session/cookie with ajax request by default, but I think it should not be a big problem if not, to append it.
When you will process /api request you should validate cookie/session also for the token existance.

Related

What is the best way to check where/who a HTTP request has come from using PHP?

I am currently building a shopify app which I have also built an API along side it. I am wanting to somehow make sure only certain website's have access to the API. I was thinking of checking the origin or refer but these can easily be faked in a HTTP request. I also thought of giving each website an access token of some sort but then they could give this out to other websites to then use the API?
So my question is, what is the most secure way to check where the request has come from?

php / apache, is there any way to block cross domain post

I have some ajax page with php post (so that CAPTCHA is not a good idea).
some fsockopen or curl could set POST value to steel data with cross domain.
So php / apache, is there any way to block cross domain post?
You are publishing the data. You can't stop people requesting it.
If you want to keep it secret, require authorisation before allowing access.
There are various barriers you can put in people's way—while still keeping the data public—but none of them are difficult to bypass. Testing the user agent doesn't stop the requestor specifying a user-agent that matches a common browser. Requiring a cookie from another page on your site doesn't stop them requesting that page and getting a cookie for their tool. Etc.
A lot web services that offer an API, but don't want just any old person to access the API, use public / private keys via CURL. You would have to do a little research on public / private key encryption if you are not familiar. I am sure there are PHP libraries that get all if not most of this done for you.
Credit card merchants like Authorize.net, and several customer database services that handle PII (Personally Identifiable Information) that I've worked with over the years allow you to post to a URL and retrieve the result. They protect their services using public / private key encryption. They issue me a key and I have to post that key along with my request data. The key is usually sent in a header, hence the need to use CURL.
Background Information:
http://computer.howstuffworks.com/encryption3.htm
PHP Examples:
http://www.joeldare.com/wiki/php:php_public_private_key_cryptography
Note: the benefit of this system is that you have absolute control over who is allowed to post to the PHP script on your server. If you don't need that level of control, you can just use something called "http basic auth". Place your sensitive scripts in a directory and protect it with .htaccess authentication. Here is a tool to get you started. http://www.htaccesstools.com/htaccess-authentication/
When you make requests via ajax (jquery, I take it) you can pass the login and password. Just make sure you use an SSL connection in your ajax (HTTPS). Otherwise, people can sniff out your login and password as it will be sent in plain text without the use of SSL.
If you do use basic auth instead of public/private keys, your domain will need an SSL cert if it does not already have one. You can buy one from someplace like Thawte.com (not cheap), or self-sign your own certificate. However, if you're going to go through all that trouble, you're 80% to the point of just going the public/private key encryption route. Self-signed certificates usually prompt the user's browser with a warning. This scares away a lot of people.

How to secure a site and internal API?

Excuse me if the title is plain idiotic with respect to the contents.
We were debating a model for an interaction-heavy site in which there will be
site.com
api.site.com
on the same server. the site.com is powered by PHP and api.site.com will be powered by an alternative web framework. The same or different servers answer the two domains.
The rendered site makes AJAX calls to api.site.com.
Securing this is easy if the application were 'all PHP'. The session feature can prevent HTTP requests that allow:
an unlogged stranger from accessing a user's data
a legitimately logged-in user from requesting another user's data
Question 1: How do you secure the internal API so that we can be sure about the legitimateness of each request?
I have googled up AJAX and same origin policy, but I didnt get far with them.
I am thinking randomly generated 'tokens' that will be acknowledged by both domains.
Question 2: Is there a specific name for this model?
You should take a look at JSONP. jQuery has a good example on it: http://api.jquery.com/jQuery.getJSON/
You need to add jsoncallback=? to the URL to make it work.
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?"
With this, you can avoid the Same origin Policy
The jsoncallback will be a timestamp, which should be echo-ed by the PHP script which outputs the JSON like this:
jsonp1277656587731(/* rest of the JSON here */);
With the number here ofcourse being the randomly generated string, or timestamp in case of jQuery JSONP

Distributing and using API-keys for web-applications

I have a web-application for which I'm building a Drupal module that allows my customers to access certain data on my application.
I intend to distribute secret API-keys to my customers who need to enter that value in their copy of the Drupal module. This Drupal module then talks to my web-application, but I need to make sure that the POST requests are indeed coming from that source.
How can this 'secret key' be used to pass some information that when my application receives it, it knows:
(a) its from that client's server.
(b) it hasnt been eavesdropped on / copied and used by someone else?
Should I be using this API-key as a password to encrypt some data that matches the rest of the POST request? When receiving it, I decrypt it using my copy of their API-key and it if matches the rest of the data, I consider it validated?
Is there a frame-work that does this for me? Something within Zend?
Use HTTPS and just send the API key in the request. It's that simple.
If you use HTTP then you are going to reinvent the wheel.
Update:
Here is an update after reading the comments, because in the question you didn't explain that you want to give the API keys to visitors of the website (in which case you would be screwed no matter what you do).
The comment by juanpaco explains what to do (and what I originally assumed that you're doing anyway) but I'll try to explained it in a little bit more detail.
The most important thing is that you don't use the API key in the web form. The API key is only used in the communication between your customers servers and your API server.
Here is a simplified explanation:
You give your customer a key and some software/module/library to install on his server.
When a visitor visits your customer's website he sees some HTML generated by your module that does not include any API key and can communicate only with your customer's server (with HTTPS if there is any sensitive information or user accounts involved at all).
Your module on the customer's server gets the request from the visitor.
Your module connects to your server using the API key (with HTTPS).
Your API server responds to the customer's server.
The customer's server responds to the visitor.
Your API key is never sent in the cleartext and never given to website visitor.
This is the only reasonable way to use API keys and after I first read your questions I assumed that you are concerned about the safety of sending your API keys between your servers and the servers of your customers.
If your customers were to give their keys to every visitor of their websites then those visitors would always be able to know them, no matter how hard you would try to make it. Giving visitors API keys and making them possible to use but impossible to read would be impossible. Not hard - impossible. No matter what protocols, encryption or anything you use.
(Thanks to juanpaco for bringing this old answer to my attention.)
Collect and store every client incoming url(e.g. www.authorisedclienturl.com) as part of the parameters you would store on your server before generating an API key to be shared with the client.
The client will use HTTPS to send the API key in the request boby from their registred authorised client urls only.
Use the API key to decript the client information on your server and retrieve the registered client url, verify that the incoming request url is present in the registered urls, then accept and proceed with other processes.

How to validate a user through an AJAX request?

We have a webpage that we provide to partner companies via an iFrame. The iFrame contains several javascript files that make ajax requests to our server for data. The iFrame itself requires an API Key that is keyed to the domain of the partner. This prevents the iFrame from displaying if it is installed on a domain that isn't registered. However, it would be pretty easy to simply copy the contents and javascript files of the iFrame from a registered site and host them on a non-registered site.
Ideally we'd like to use the API key to restrict Ajax requests and prevent our server from providing the requested data for non-registered sites. However, it appears that the HTTP_REFERER server variable is not set for Ajax requests. How can we tell what site that the request is coming from? Is it possible? If not, how can we prevent unauthorized access?
Relying on HTTP_REFERER isn't the way to go. You want your client's website to use an API to contact your website over a secure link, and get a temporary session string, which is then used as part of the source url for the IFRAME, which is how google does it (not with referer.)
Make the url for the IFRAME valid for a limited time, after which you display a nice message about going back to the client's page to start over.
When the iframe is requested you can generate a unique ID on your server, then set that as a cookie on the client. Every AJAX request should contain that cookie. Only keep around the ID's for the last hour or so.
You can never rely on HTTP_REFERER because some proxy servers and firewalls will strip it out to preserve users' privacy.
The challenge is that the iframe is authorized to a specific domain, so my API Key is tied to that. I followed the following tutorial to generate my API keys.
https://ajax.dev.java.net/ajax/api-keys
Do you think that relying on the HTTP_REFERER variable will prevent users from accessing the iframe? Sun claims that Google uses this method for Google Maps API authentication.
Once the API key has been authenticated, then the cookie approach should do the trick, I think. Thanks!

Categories