tags:

views:

753

answers:

7

I have a web application that pulls data from my newly created JSON api.

My static HTML pages dynamically calls the JSON api via JavaScript from the static HTML page.

How do I restrict access to my JSON api so that only I (my website) can call from it?

In case it helps, my api is something like: http://example.com/json/?var1=x&var2=y&var3=z... which generates the appropriate JSON based on the query.

I'm using PHP to generate my JSON results ... can restricting access to the JSON api be as simply as checking the $_SERVER['HTTP_REFERER'] to ensure that the api is only being called from my domain and not a remote user?

+3  A: 

Any solution here is going to be imperfect if your static pages that use the API need to be on the public Internet. Since you need to be able to have the client's browser send the request and have it be honored, it's possibly for just about anyone to see exactly how you are forming that URL.

You can have the app behind your API check the http referrer, but that is easy to fake if somebody wants to.

If it's not a requirement for the pages to be static, you could try something where you have a short-lived "key" generated by the API and included in the HTML response of the first page which gets passed along as a parameter back to the API. This would add overhead to your API though as you would have to have the server on that end maintain a list of "keys" that are valid, how long they are valid for, etc.

So, you can take some steps which won't cost a lot but aren't hard to get around if someone really wants to, or you can spend more time to make it a tiny bit harder, but there is no perfect way to do this if your API has to be publically-accessible.

matt b
This is probably the most elegant work-around, but I agree it's only a work-around and not a real solution (there is none).
Matthew Flaschen
So what you're saying is that ... if I checked the 'HTTP_REFERER' - that at least provides ***some*** limited assurance that only my website is using my JSON api. But then again, the 'HTTP_REFERER' can easily be faked.
JamesZ - correct.
matt b
A: 

The short answer is: anyone who can access the pages of your website will also be able to access your API.

You can attempt to make using your API more difficult by encrypting it in various ways, but since you'll have to include JavaScript code for decrypting the output of your API, you're just going to be setting yourself up for an arms race with anyone who decides they want to use your API through other means. Even if you use short-lived keys, a determined "attacker" could always just scrape your HTML (along with the current key) just before using the API.

If all you want to do is prevent other websites from using your API on their web pages then you could use Referrer headers but keep in mind that not all browsers send Referrers (and some proxies strip them too!). This means you'd want to allow all requests missing a referrer, and this would only give you partial protection. Also, Referrers can be easily forged, so if some other website really wants to use your API they can always just spoof a browser and access your API from their servers.

Laurence Gonsalves
I don't want encrypt it, I simply want to restrict "who" can call my JSON api. The only person I want to be able to call the API is my own web server and no remote users.
Yes, that's what the last paragraph of my answer is about. You could try using the referrer, but it can be easily spoofed.
Laurence Gonsalves
+9  A: 

The usual method for restricting access to your domain is prepend the content with something that runs infinitely.

For example:

while(1);{"json": "here"} // google uses this method
for (;;);{"json": "here"} // facebook uses this method

So when you fetch this via XMLHttpRequest or any other method that is restricted solely to your domain, you know that you need to parse out the infinite loop. But if it is fetched via script node:

<script src="http://some.server/secret_api?..."&gt;&lt;/script&gt;

It will fail because the script will never get beyond the first statement.

fearphage
Say what? Your recommendation is to create an infinite loop? Either I'm completely missing something here or you're pulling my leg.
Except anyone can still call it from server-side code without any hassle and just strip out the loops.
Matthew Flaschen
Yes, JameZ, that is correct. An infinite loop prepended to the JSON will prevent your JSON from being loaded into script nodes. Yes, it will not prevent access from the server-to-server. This is not a fix-all solution. It is just another layer of security. It will prevent your data from being loaded client-side using the script node.
fearphage
I can load it with an xhr, remove the loop part and then add it to a newly created script block, can't I?
Amarghosh
Amarghosh: Your explanation works from the same domain. However, xhr is domain restricted. To answer your question: No, you cannot.
fearphage
+10  A: 

I think you might be misunderstanding the part where the JSON request is initiated from the user's browser rather than from your own server. The static HTML page is delivered to the user's browser, then it turns around and executes the Javascript code on the page. This code opens a new connection back to your server to obtain the JSON data. From your PHP script's point of view, the JSON request comes from somewhere in the outside world.

Given the above mechanism, there isn't much you can do to prevent anybody from calling the JSON API outside the context of your HTML page.

Greg Hewgill
If that's the case, how are people projecting their "RESTful" api's? Or are these API all public?
Generally, they are public APIs. Depending on the website, they may or may not be documented for public consumption, but they should all be constructed with an eye toward robustness in the face of malicious (or just undesireable) users.
Greg Hewgill
So how do people prevent users from submitting a REST query that simply dumps all data from the web applications database.
The API would be designed in such a way that there is no ability for the calling user to do things that you don't want done. For example, a poor JSON API would accept a SQL "where" clause and pass it straight through to the database. Even if it were sanitised and safe from injection attacks, you may not want your users being able to query for any range of records. A better API might accept a record ID or keywords or something and return a maximum of 10 records. The key is, you can't trust anything coming from the outside world.
Greg Hewgill
+2  A: 

in my opinion, you can't restrict the access, only make it harder. it's a bit like access-restriction by obscurity. referrers can be easily forged, and even with the short-lived key a script can get the responses by constantly refreshing the key.

so, what can we do?

identify the weakness here:

http://www.example.com/json/getUserInfo.php?id=443

the attacker now can easily request all user info from 1 to 1.000.000 in a loop. the weak point of auto_increment IDs is their linearity and that they're easy to guess.

solution: use non-numeric unique identifiers for your data.

http://www.example.com/json/getUserInfo.php?userid=XijjP4ow

you can't loop over those. true, you can still parse the html pages for keys for all kinds of keys, but this type of attack is different (and more easily avoidable) problem.

downside: of course you can't use this method to restrict queries that aren't key-dependent, e.g. search.

Schnalle
A: 

Sorry, maybe i'm wrong but... can it be made using https?
You can (?) have your API accesible via http**s**://example.com/json/?var1=x&var2=y thus only authenticated consumer can get your data...

NilColor
SSL doesn't guarantee identity, it just prevents 3rd parties from seeing your data while it is in transit between browser and server.
RQDQ
A: 

Are you, or can you use a cookie based authentication? My experience is based on ASP.NET forms authentication, but the same approach should be viable with PHP with a little code.

The basic idea is, when the user authenticates through the web app, a cookie that has an encrypted value is returned to the client browser. The json api would then use that cookie to validate the identity of the caller.

This approach obviously requires the use of cookies, so that may or may not be a problem for you.

RQDQ