api security implementation php - php

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

Related

How can I redirect user to API endpoint (different domain) using server IP instead of user IP?

I'm doing a soap request to an external API using Laravel & Guzzle. All other calls have succeeded to get the actual response but for the redirecting user to the external page has failed because the external API web service only allows my server IP to access that page.
I have tried:
windows.location (javascript)
location header (PHP)
return redirect URL (PHP)
This is their documentation on how to redirect in VB language :
redirection code in VB
All of these methods only use the browser redirection which is using user IP not the server IP.
Any method that I can use to redirect user using my server IP that you guys can recommend?
Thanks in advance.
Extra context/information:
Example screenshot for the fourth call which include get the quotation number and generate the url parameter
That is the code for VB that they provided in API documentation. So why I want to bring the user to the page? It is because when the GetQuotation (fourth call) is already submitted to their database and it will return QuoNo that will be used in the URL parameter. When the user gets redirected to the external page with parameter QuoNo=12412194149124, their backend will query for the quotation details that the user fills in my side (mydomain.com/form) and auto filled it on their side (otherdomain.com/form).
If you see from the screenshot, the System.Diagnostics.Process.Start will execute the url once the Quotation number (QuoNo) is generated. So once the user click on the 'buy now' button on our end (mydomain.com/form), it will call the fourth call (GetQuotation guzzle function) and generate a Quotation Number (QuoNo) then it will be populated in http://otherdomain.com/main.a5w?tokenid=wm-9Kj-14e-Fa4-I1adlXrQ00weqwe3S&QuoNo=QUO022348921312301623. Based on what my understanding on VB code, System.Diagnostics.Process.Start will force the url to be opened.
I'm sorry if it's still lacked of info given. Feel free to ask more. Thank you
What you want can not be achieved sadly. The only thing you can do with the redirect is tell the browser where to go, you have no control over the IP here since this would pose all kinds of issues regarding security and identification. The only way to achieve what you want is to wrap the html of the resulting webpage in your website or remove the restriction of the ip addresses. Another solution could be to build a simple page which is accessible to everyone and limit the API routes to specific IP addresses. For example:
Let's assume the payment gateway is at: example.com/checkout, this one would be accessible to everyone and would contain a form to which you can perform the redirect and fill this form with the passed data.
This form would then post the information to example.com/api/v1/checkout which will process your form data and return if the transaction was succesful. Based on this return the user will be redirected to another page. This is assuming you have control over the other domain since only with your server IP you can access this site.
If this is not the case there is no other way than to post the data to an endpoint via guzzle and use these return values to provide feedback to the user.
I hope this answers your question, if anything is unclear please let me know.

Security of requests from android app to server

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 :)

OAuth authentication in twitch.tv with php

I've seen similar Questions like this before but don't understand the correct way of doing it. Or rather the questions were always a little different.
The scenario: I have a site where the user should log in via twitch.tv
I have a button which refers him to this url
https://api.twitch.tv/kraken/oauth2/authorize?response_type=code
&client_id=exampleclientid
&redirect_uri=http://example.com
&scope=user_read
I have censored redirect_uri and the client_id but basicly on this site the user needs to login into twitch or if he already is he can authorize that my application gets acess to "scope" here in this case "user_read" which is his email adress.
Now to my problem. When returning to my site my url will look like this
example.com/#access_token=exampleacesstoken&scope=user_read
example acess token is just a combination of numbers and letters which I need to acess private information like his email even his username.
Over this url
https://api.twitch.tv/kraken?oauth_token=exampletoken
I get acess to my needed information, but how do I grab the token from my url via php and delete everything after http://example.com to make it look good again.
The offical API documentation might be helpful and talks about CURL but I don't understand how it works and the PHP manual is very indepth.
https://github.com/justintv/Twitch-API
Sorry if I'm taking the lazy way here, but I think I'm missunderstanding something big because I just have to make a simple grab of the URL
From the Twitch documentation:
https://github.com/justintv/Twitch-API/blob/master/authentication.md#implicit-grant-flow
If the user authorizes your application, they will be redirected to
the following URL:
https://[your registered redirect URI]/#access_token=[an access
token]&scope=[authorized scopes]
Note that the access token is in the
URL fragment, not the query string, so it won't show up in HTTP
requests to your server. URL fragments can be accessed from JavaScript
with document.location.hash.

How to do API authentication with curl

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.

Creating a PHP API: Checking from which server the API Request comes from

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.

Categories