I'm new to creating API's and I am making an API for my php site. Now in any case what I am currently doing is having my script do a cURL call to some php file which does all the processing. Aka im doing a POST call for example to an api file which lets say creates a forum post for that user. Now the important thing to me is how do I authenticate and retrieve which user is sending the data. So how do I know the cURL call came from my server?
What I was going to do is have my server have a secret key that is passed in the api call and verified by the api file. The api file would make sure the key is correct and then take whatever username was passed in for example to make a forum post. My only concern is if this key is ever found out im screwed. I also want to be able to have the site work lets say as an android app so I want to be able to make curl calls lets say (not sure if thats possible) and have some authentication key sent to my server but I never want the user to be able to packet inspect for the secret key.
So my question is how can I securely do curl calls, since when I do a curl call it doesn't read any of the $_SESSION values I have set (unless im missing something). Any help is much appreciated. I was also thinking of authenticating using the username and password each time the only problem is I kind of want to avoid having to verify that the username and password is correct every time an api call is done since thats going to be another query that has to be done. But if that is the recommended way or the industry way then ill do it that way. Just looking for how to handle everything the proper way.
You should look into implementing OAuth then.
Related
I have an android app and a php server. I send some requests, say for login and other request parameters as required by my app; and the server sends back json which is displayed in the app.
My question is how could I prevent other users from accessing the urls via the browser and getting the results?
Also most of the requests should only execute if the user is logged in. That is taken care of in the app but how in the apis? I can send an auth token to be sent along with further requests, but the same can be get by calling the login api via browser and then sending that login token with other apis. How to handle these situations and prevent access via methods other than the app to get the data?
And also does it matter in case of android apps whether I send the login password encrypted or not from the app? Or should they be encrypted at the server and then stored in the database?
This might be a very naive question, but I couldn't find an existing one here on SO. P.S. I know php apache server is not the best option but the client has an existing php server ready with the apis and he wants to use the same in the app.
With my experience in writing a JAVA REST API here are the few suggestions I can make,
1> My question is how could I prevent other users from accessing the urls via the browser and getting the results
ans: If you want the API to respond to only the requests sent by App, You can sign the request with a unique key which is known only to the app and no body else.
For example: You can generate a string by appending all the parameters you send in a specific order like username+password+param1+param2 and then apply SHA 256 or any of the hashing on that string to generate a unique string and send this string as a Authorization header value :)
At API end because you know the oder of the parameter to join, once you recieve a request regenerate the string using parameter that you have received and apply same hashing on the string and check whether the string you generated matches the request Authorization header value or not and respond to only one with proper Authorization value :)
How it works : Being un-aware of Authorization header whenever browser makes a request this vallue will not be there in request hence your APU wont respond.
On the other hand if somebody deliberately tries to track the request and realizes that Authorization header needs to be sent, still wont be able to get response from your API because he will not know the Algorithm used to generate the value nor the sequence of parameter used.
Use Cases:
All Outh API's makes use of same pattern. Read OAuth specs for clarity (Though they use ot for different purpose, you can use it to benifit your situation:) )
Example of API's : Facebook,Twitter,Google,Linked In and so on :)
2>also does it matter in case of android apps whether I send the login password encrypted or not from the app?
Ans:
It does not matter wheteher you use android apps or web browser to make request :) If you are using POST request all your parameters will be encrypted by default :) So dont worry about it :)
3>should they be encrypted at the server and then stored in the database
Ans:
Saving a password in a plain text at your data base can lead to many consequences :) So its always better to save encrypted passwords at data base :) As far as usernames are concerned its ok to save them in plain text :)
Extra peice of Info : Make sure all your api's makes use of Secure channel :) I mean make sure your API's are https :)
Hope my suggestions helped :)
So I'm trying to get the latest tweets posted by a user using a PHP script (and caching the results into a text file). I'm using the request https://api.twitter.com/1/statuses/user_timeline.json?count=5&screen_name=google and it's been working fine as a public client, but in order to get better control over my API hit limit I need to authenticate my requests.
I've tried the method shown at https://dev.twitter.com/docs/auth/application-only-auth , but after I successfully connect I get the error "Your credentials do not allow access to this resource" (why ?). So I've tried to use the OAuth method (which looks frighteningly complicated for a hobbyist like me), and downloaded the TwitterOAuth library. But I'm still having trouble connecting ! I put my credentials in the config.php file, but I have no idea where to go from there. The documentation seems to be hinting that I need to manually login to Twitter to authorize the application's connection token... or something. Apparently I need to redirect to some callback URL (what even ?!) and get a short-term connection to enable a long-term connection password which I have to store for later ? What is this madness ?
I was initially under the impression that I could just fetch data from Twitter's RSS feeds but those can't be accessed from scripts for some reason (unlike the Google News RSS feed which fetches just fine). It seems I've gotten myself into something much more complicated than what I signed for. Isn't there an easier (and saner) way of doing this ? Or is nothing decidedly simple ?
I apologize for being such an easily-confused dullard, but my head is spinning.
Thanks !
Edit : after digging around some more I decided to just use PHP curl to fetch the raw page, and then do some Xpath voodoo to get the tweets and the time they were posted at. Of course, this is CPU-intensive, far from stable, and probably not a practice that pleases the folks at Twitter; it also only returns the last 20 tweets (which is thankfully enough for my needs).
However, Cormac Driver's response below about Temboo is certainly a method I'll be investigating next time I need to do something like that.
Temboo provides a simple way of using OAuth to authenticate with Twitter. The process is broken down into two steps:
InitializeOauth. This step returns a Twitter authorization URL that Twitter account holders can visit to grant access to your script.
FinalizeOauth. This step returns the access token that your script will need to make authenticated requests to the Twitter API on behalf of the user.
Full details on how to do this with PHP here: https://www.temboo.com/library/Library/Twitter/OAuth/
You can see an example of how Temboo handles OAuth for Facebook on this page. The PHP source code is provided, and it's almost identical to the code you'll need to do the same thing for Twitter.
(Full disclosure: I work at Temboo)
I am working on a PHP REST API. I would like require a user key to access the API. I am not sure how to do this though, do I just issue a key and have them send it in a POST or with GET on each API request? Please help me explain in the simplest of terms possible if you can, I know this is something a lot of people want to do and it confuses a lot of people not just myself.
Also I would like to be able to limit usage, I was thinking of storing each hit in a MySQL database or something in Memory even. I just saw this in the header of a Github API request
X-RateLimi-Limit 5000 and X-RateLimi-Remaining 4996 and the number decreases by 1 on each hit, is this some kind of built in limiter?
Just require clients to register with your site,
create a record in your CLIENTS table, issue them a unique, non easy to guess id
then with each api access require that id to be included in request, either in GET or POST on in the header.
Validate it with every request, return error code if id is not present or invalid.
For rate limiting you are correct, you need to have a separate table for storing count of requests per client and then generate these response headers with X-RateLimit counters.
It's not that hard, really.
I wrote an API that does that for my project, you are welcome to look at the source code, it's in the Api folder, here
https://github.com/snytkine/LampCMS/tree/master/lib/Lampcms/Api/
and entry point to API calls is this
https://github.com/snytkine/LampCMS/blob/master/www/api/api.php
url for adding new app is:
http://support.lampcms.com/index.php?a=editapp
I have a site that allow users to check their statistics (number of file uploaded, how many files they have, quotas, type of access etc...)
I create a section on my site: api.domain.com
This can be access via curl or a web browser since I am returning a json object or xml (depending on the user prefs)
My question is this: should I restrict the access using a user/pass or should I create a hash of the user file?
for example:
scenario 1:
The user create a php curl that sends user and pass via post or the curl auth and get back the results, parse it etc...
For me this is secure but the user has to maintain his script if they change their pass
scenario 2
The user access a file like: api.domain.com/j355HGssgf3HESAjh45jusf4325GSj5hbsHhdh5HGHFS3732he4548475wbe3447nSNe5XfgjhGJ and then access the data
This one, nothing to maintain
Here's my thoughts on this.
If you return a page not found or an error message (with a good 200 OK status) when a request is made to your page, it might send to bots or UN-trustable people a clue on what can they get and try again and again and again ...
On the other hand, if you send a access denied, like a 401, or better a 500 error code to simulate a server error, these bots or UN-trustable people might go away for good.
I will say the user/password method is a little more secure in this case.
Now, would you trust simply entering a big string (like scenario 2) when you check your mail? or your bank account information?
If it was me I would give each account the ability to create a unique api key,
api.domain.com/?key=<API.KEY>
for more security measure you could make it only accept connection via the post method with the api key. If contacted via get then show an error etc.
Then if they change their pass/username it won't affect their api key
I'm creating a PHP API for a website and I'd want to restrict the API access to domains that are registered on our server (in order to prevent abusing of API usage). So, this is my approach right now, and well, it should look pretty good on paper.
The API is setup at api.example.com.
A user that wants to use the API registers with us, adds his domain and gets an API key.
The user of the API will use his API key to encrypt his request data (via mcrypt) and sends it, via cURL to api.example.com.
My server checks from which domain this API request comes from and matches that domain to an API key in the database. If there is an API key, the API decrypts the request via mcrypt with that key and then using the same method encrypts and sends the result.
I'm stuck on step 4. Originally, I planned to use HTTP_REFERER to check it, but since cURL doesn't send one by default and it could be easily faked in the user-side code (CURLOPT_REFERER as far as I remember), I am stuck here.
Is there a method to know from which domain this API request comes from? I see that it can be done with some popular APIs like the reCAPTCHA one. Checking the _SERVER["REMOTE_HOST"] isn't really an option because of shared hosts (they have the same IPs) so this would not be able to prevent abuse (which would originate mostly from shared servers anyway).
Is there such a method to check for it? Thanks!
#Shafee has a good idea it just needed some tweaking. We're focusing on the visible part of the API call, which is the API key. This is visible in the URL and tells the API who is requesting the data. Rather than trying to prevent others from stealing this key and running their own cURL call with the domain they intercepted it from, we can 'just add' another key to the mix, this one not visible to those interceptors. I'm not saying stop checking where the request is coming from, it's still a good way to kick out invalid requests early on in the script, but with a second key, you guarantee that only the person requesting the data actually knows how to get the data (you're trusting them not to give it away to anyone).
So, when the user registers for a key, you're actually assigning two different keys to the user.
API_KEY - The public key that connects you to your domain. The system looks up the domain and key provided in order to find the next key.
MCRYPT_KEY - This is the key that will be used to actually encrypt that data via Mcrypt. Since it's encrypted data, only the requester and the server will know what it is. You use the key to encrypt the data and send the encrypted input with your API key to the server, which finds the key that it needs to decrypt that input via the API key and domain (and IP) that have been provided. If they did not encrypt the data with the proper key, then decrypting with the correct key will return gibberish and the json_decode() call will return NULL, allowing the script to simply return an 'invalid_input' response.
Ultimately with this method, do we even need to check where (domain/IP) the request is coming from? Using this method it really comes down to the API users not giving away their API/MCRYPT key pair to other users, similar to not giving away your username/password. Even so, any website can easily just go sign up to get their own key pair and use the API. Also to note, the API will not even return anything useful to their server unless the user on their end logs in using the correct username and password, so their end will already have that information. The only thing new our server is really returning is their email address upon successful validation of the user. Having said that, do we even need to use cURL? Could we not simply use file_get_contents('http://api.example.com/{$API_KEY}/{$MCRYPT_DATA}')? I realize I'm asking more questions in my answer...
You can varify what ip the request comes from, and you ofen can do a ptr search to get a domain name for that ip, but probely the ip adress have more then one domain, and you end up whit the wrong one, so i recomendate that the client send his domainname in the reques, maybe whit HTTP_REFERER, and that you make a dns check if that domain points to the ip asking for it, but notice that a domain, like google.com, can point to more then one ip.
(the ip could probely be faked to, whit some good hacking skill, but thats out of my knowledge)
How about introducing a second variable like lets say an app id. When a user registers her domain, associate this id with the domain. The user needs to submit the app id with each request without encryption along with the encrypted api call. Then you can look up the app id get the app secret and try to decrypt?
In order to best prevent abuse of your API, limit either the speed of requests, or limit the number of requests they can make. If someone is stupid and shares their API key, they'll only be limiting their own API usage, making it more economical for people who intend on abusing the API to get their own key.
Plus, what if someone decides to implement a desktop application using your API? Surely they won't require their users to send their IP addresses to them so that they can whitelist them?
Also, you can combine limiting speed/limiting requests, and limit speed based on the number of requests like how Verizon limits the speed of their 3G network if you pass a certain amount of data usage.