How to secure a php based webservice - php

I'm developing one android application and I'm creating a php based webservice to retrieve the information from the database.
The thing is that I really don't know how to secure this service.
For example, if my android application needs to retrieve some information from the server it will call http://mywebservice.com/service.php, and it will send several POST parameters as the user and password to login, or something like, for example, one user id to retrieve his data.
Of course, anybody with the knowledge enough will be able to retrieve that data too. And this is what I don't want to happen.
Anybody who know the parameters to send to my server will be able to retrieve information from it.
How can I secure this?
I've been reading about OAuth, OAuth2, two legged and three legged implementations of it, https..
But at the moment, I really don't know how to secure this.
I want that the webservice only answer to my application and not to anybody else.
PS: Even there is something like http://myservice.com/get_information.php that you send an id and you can retrieve a lot of information. Of course, I control that in my application, only logged and authorized people can do that calling, but it's a problem anyway. What's the best way to do this kind of things?

Some concepts to secure a webservice(might be forgetting some notions):
Protocols: HTTPS in the current case so data are not transfered in a clear format.
The Sessions: A session has a lifetime, a unique identifier(session token/id/whatever) and contains an error code. When a user will call your webservice, a session will be created and its token answered back. At every call of the webservice you'll test if the session is still alive. You can add complexity to the expected inputs, outputs and exchanges. The error_code will be used for logging(errors can come from an attack or a bug of your webservice).
Data Encryption: Use asymetric functions like password_hash() or crypt() for authentication issues. Use symetric algorithms like AES 128(10 rounds) or 256 (14 rounds) for sensitive data you'll need to retrieve.
Testing inputs: If you find yourself inserting given arguments in a query, try to prevent SQL injection. Some bad-minded people can also try to send arguments which would make your webservice fail.
Go for standards: As Çagatay said, try to implement for example oAuth2 because standard is most of the time much better than what we'll build :S
Hope it helps.
edit: The REST security sheet is good also.

Always use SSL to prevent some man-in-the-middle attack. Otherwise someone that sniffs the connection (in case of connecting via public wi-fi or company networks it's a huge risk) can see the username and password.
Do not send username and password on each request, instead implement oAuth2, your client in this case will have to send the username and password only once and then for the other requests you'll have to send only the auth key. Good documentation for implementing a oauth server: http://www.sitepoint.com/creating-a-php-oauth-server/
Look at this document: https://www.owasp.org/index.php/REST_Security_Cheat_Sheet

I ended using OAuth. More especifically this library https://bshaffer.github.io/oauth2-server-php-docs/
If you follow the instructions it's really easy to use and it works very well. I think it's a really good way to start working with OAuth.

Related

A simple method to secure a simple read-only API

I have built a simple read-only API for our database, so that users can retrieve data from our database.
For example, the URL "http://xxxxx/getAllProfiles" will return a JSON result containing all profiles stored in the database.
The API is read-only, it is only implemented with some 'select' SQL queries. Thus the user cannot modify any of the data in the database via the API.
My company worries the API will be exploited by some random bots online, and has been asking me to build a security mechanism for this API. (It is worried if there is no key or something that prevents anyone from accessing the URL, our server would be visited too much. It is a small server.)
What would be the simplest secure mechanism that I can implement, using PHP? (We are also using Slim for the API, Amazon EC2 server with Ubuntu and Apache running on it, if this helps.) Preferably it can be implemented without the use of any database on server or client side.
If there's anything not clear, please let me know, I'll clarify.
Thanks.
Add:
Thanks for the comments.
Is there a way to NOT use a database? Like a smart way to generate a key or something... I'm thinking I'll provide a page so that user can input the domain, and an algorithm will convert this domain to a key. Then, for each request, the user should include this key. The server will grab the domain from the request header and use the same algorithm to calculate again. If the two calculated key matches, the request is accepted. I think this, at a minimum level, ensures that at the beginning there must be someone to input the domain and get the key, thus filtering some random bots out?
I am not sure if this is secure (at all)? But it sounds to me like it can filter out something.
I posted this question when I know very little about web development.
There are many ways to secure a REST API, e.g. JWT, Cookie, Basic Auth, etc.

Session integration, is this approach secure?

A user logs in using default Laravel authentication, which puts an encrypted cookie in the browser, and saves the session in the database.
The user moves to a classic asp page, where I check the cookie value, get the hash, and call the laravel app back passing the session id hash.
Then I use that in laravel to see if there's an active session for that id, and if so I return true, so the user can be logged in, in classic asp.
On each page request in the classic app, I check the last_updated_time in the db and update it on each page. All logging in and out is done in laravel, and classic relies on the database to see if a session is active.
I would also call a public url to get sessions variables and add session variables using laravel, since it's all encrypted and using classic asp for this would be hard.
The only risk I see is session highjacking, but I don't think it's a higher risk than usual.
Is it important to lockdown the laravel URL I call to check if it's a valid session?
Am I missing a security hole here?
Is this method secure?
From what you've stated you probably haven't opened up any security holes. The session cookie is not itself encrypted on the users machine, but you are making sure it is encrypted between their machines and yours, as well as between each of your machines. You should make sure you've set the Secure Flag to help prevent the cookie being accidentally sent over traditional unencrypted transport (HTTP), but as stated, this doesn't effect storing the cookie itself.
That being said, you are essentially hijacking your own users sessions. While a hole might not be introduced now, you are potentially weakening the overall system, which could lead to hole in the future.
Is there a better way to do it?
This might well be a dumb question, but are you sure you need the session? If you're juggling credentials between servers, it sounds more like you want to use Access Tokens and scrap the session.
Using Access Tokens is similar to using sessions, but you need to make your services stateless. This means your no longer storing information about the logged in user any specific machine so you'll need to pull anything you need from the database every time they hit a server requiring that information.
This is a good thing in the long run as it's much easier to scale your services when you don't need to worry so much about where the session is and what's inside it.
OAuth 2.0 is widely used standard (Facebook, Twitter, Google), and was specifically designed to be easy to use. The RFC is complex, but there's a log of good guides out there don't worry.
The one slight down side (if you can call it that) to OAuth 2, is that it MUST happen over an encrypted connection. If your use case can not guarantee encryption over SSL or (preferably) TLS, then you should use OAuth 1.0 (WITH revision A) instead.
This is due to the fact that OAuth 2.0 exposes it's "secret" token in requests, where as OAuth 1.0 only ever uses it to provide a signature hash. If you take this route it's advisable to use someone else's library as the hash is very, specific.
Further Improvement
(Note: This section added after the answer was accepted)
One system I've been exploring recently is Json Web Tokens. These store information about the user to save each machine repeatedly looking it up in a database. Because the token is hashed with a secret, you can be sure that, so long as your secret isn't exposed, a valid token represents a successfully logged in user, without having to touch the database.
You should avoid putting anything too personal in the tokens if possible. If you must store private or secret information in the token, you can encrypt it, or you can use a reverse caching proxy to exchange the JWT for a traditional security token. This may initially seem to defeat the purpose, but it means some of your services may not need database access at all.
I'm no security expert but I don't see an issue with this. The packaged Laravel database session handler works the same way. The cookie contains a hash that references a record in the database. The session data is base64 encoded but that's neither here nor there. I think you could actually avoid rolling your own and just use Laravel's DatabaseSessionHandler.
Illuminate/Session/DatabaseSessionHandler
... I just read a little deeper into your question and noticed the part about the public URL to set and retrieve session data. I think this is a really bad idea. Mostly because it will provide an open door to the end user allowing them to read and write session data. This can only end badly.
Like I said above, the data is only base64 encoded so I believe you'll be able to parse, read and write that to your hearts content within asp.
Edit
Ok... I think this is the last edit. The data is php serialized and then base64 encoded. This question looks like it may help you to that end. If it doesn't and an API endpoint is the only way, find some way to block the end user from accessing it.
Aside from session-hijacking, no. This is the standard way applications interact on a internal basis. Of course there might be a better way to get at the data if you choose a different type of session store other than your database, Memcached for instance.
There are couple of things that can be done.
Make the channel HTTPS. It will make almost impossible to sniff on your transport layer.
Rather than making interactions with your cookie, you could use a JWT to get this task done. Which will help you to use the existing functionality in your system while connecting with ASP system as well. You can write a small REST web service which allows ASP to connect. You could use this lib. You can refer this article which will give you an idea how it should be done.
Please let me know if you need more information.

Android(ios) to PHP API Security

I am doing a RESTful API design for android using php. Because of this, I am creating PHP API's which will go into my Database and serve specific data based on the method/function called.
but after reading some tutorials,I encounter some quetions and I can’t find a good way to solve my problem.my question is as following:
1.how can I maintain the session between my API and android.In other words,if the user login the system through android,how can I maintain the session?some use PHPSESSID and others use userid(returned by the api),which is better?
2.how can I protect my API from misuse?I find many use apikey
3.how can I protect malicious user tamper the data?this is related to my first question,if I use the userid to maintain the session between my API and android,based this,even if i use apikey, malicious user also can tamper his userid to other’s,so he will get other’s infomation .
I am stucked so much,so please help me?
I recommend you to read About HMAC authentication.
You will don't maintain the session... every request to server will send some token data in the request header.
You can work on it, thinking in ways to protect your server. The most important think is to follow the best practices and when your software are in production check your logs often.
Use the HMAC or some similar method.
You need to change your mind to don't store sessions, and follow the API best practices. I good idea are read the instagram, facebook, g+ and gdrive docs to see how they do.

How do I authenticate users with a site API?

I want to build an API for users to build applications that easily interact with a site, and I was wondering what the best way to authenticate users would be.
Taking a look at other API's a lot of them have the user send the username and password as a GET parameter over a HTTPS connection. Is this the best way to go about it? Or are there other methods that I should look into or consider?
I've seen OAuth been tossed around and it looks like a good solution, but just for a simple API is it overkill?
You can use API key's. Generate a unique hash tied to an account upon request. Then check that the key is a valid key. As long as the API doesn't have any major security issues with someone using someone else's key then Authorization isn't needed. If there is a problem with someone using someone else's key then Authentication would be justified.
This is usually achieved with cookies.
The client sends their username and password with a POST request to your API (do not use GET, that's insecure). If the credentials are acceptable, then generate a random, unique session key, store it on your side and send it in a cookie back to the client (see setcookie()).
When the client now makes further requests, they send the session key cookie with the request. Check $_COOKIE for the session key if it matches a stored key on your side; if yes, that means the user authenticated.
Take note that this minimal example is vulnerable to brute-force attacks trying to guess valid session keys. You need to log invalid keys that clients send in their cookies and block their IP address for some period of time to prevent this.
Username / password in a GET isn't a great way to do this because you're potentially exposing the whole user account for hijacking even if the API has more limited functionality than logging into the site. So it's good practice to separate concerns between Web-site login and API access.
I'm not sure which case you're in but:
If the users are business customers of somekind who are embedding some type of widget or code in another website then it's probably best to use an API key which is scoped to the referrer domain (much like Google Maps does).
If they are end-users who won't know anything about the API but are going to be using Apps built by third parties then oAuth is likely to be your best bet, otherwise your users might literally be giving their usernames/passwords to unknown third parties. It's more complex but likely to be worth it in the long run.
To get a bunch of this stuff out of the box you can use something like 3scale (http://www.3scale.net) and it'll handle most of it for you (disclaimer, I work there so adjust for bias!) or there are open source libraries for oAuth in most languages (in PHP Zend-OAuth component might do the job for you).

Creating challenge-response sign-in

I'm currently trying to create user authorization that follows:
The definitive guide to form-based website authentication
I already implemented crsf tokens, passwords are encrypted in database etc. Now I need to add some encryption to data being send at user sign-in (can't use SSL).
I've been looking for some some good solution but I've found only:
http://unitstep.net/blog/2008/03/29/a-challenge-response-ajax-php-login-system/
I'm not security expert so I don't want to write such system by myself (but I guess I have to).
Do you know any class / lib that provides challenge-response feature?
Data must be hashed at client side before sending to server - isn't that unsafe by definition?
After reading the article at unitstep.net, it does seem interesting.
The challenge is a cryptographic nonce, which means is only sent once to the client and after successful login, it is invalidated, so if someone were sniffing the connection and they received the challenge and the response, it wouldn't work since next time around it will be different. As far as the login credentials are concerned, someone sniffing the connection will not feasibly be able to hack your login information by using the data sent during login.
However, when not using an encrypted connection, there are other downfalls. A few I can think of are:
If a hacker got the challenge and your response, they could perform a dictionary/brute force attack on it to retrieve your password. If poor (fast) cryptography is used and a simple password is used, this may be done relatively quickly, so make sure to use a slow algorithm or use many rounds if it is a fast one to achieve a slowing effect.
This method does not provide authentication, which could lead to a man-in-the-middle attack.
Since it is done client-side, you have no control over the password strength. For all you know, they could be using an empty string.
A hacker can sniff what the user is doing while logged in
Your site would be far more vulnerable to session hijacking
Even though your login credentials are safe in themselves (since they are never transmitted), the next challenge is always stored ahead of time in the database in plain text.
Valid SSL certificates are not expensive. Doing a quick search for "cheap ssl certificates" found a few matches under $10/year (about the cost of your domain name). This is definitely the way to go if you can.
Now, to answer your actual question:
Do you know any class / lib that provides challenge-response feature?
No, sorry.
Data must be hashed at client side before sending to server - isn't
that unsafe by definition?
I don't see how this would be unsafe. I have seen a few websites implement browser-side certificate logins (such as http://www.startssl.com and Webmin also has the same feature). A certificate pair is calculated by the browser and the public key sent to the server for authentication.
Edit 2016:
If you're looking for completely free SSL certificates I highly recommend https://letsencrypt.org/. I currently use them for about 10 domains without problem and have the certificates automatically renew using a simple cron job, so now I basically never have to worry about certificates again. They also accept donations which I would encourage anyone using them to do, especially since they are saving you ~$10/year per domain.

Categories