I'm currently building an API for a very busy internet website. Its being written in PHP with MySQL. Now this is my first API that i'm writing that allows people to access their account remotely. Once the API is online, developers will be able to write their own tools from it.
Now I have the API working, but I'm not sure if its entirely safe.
An example URL that would work is: http://domain.com/api.php?api_option=list&api_user_name=USERNAME&api_user_password=PASSWORD
USERNAME: would be the users actual username
PASSWORD: would be the MD5 encoded string of their actual password.
If the details match, a result is returned, if not, and error.
All external $_GET inputs get the mysql_real_escape_string() treatment.
I wanted to keep things simple, but I'm not sure if this way is a SAFE way of having a public API that taps directly into users accounts data.
Ideas and suggestions are much appreciated.
Please, for the love of the Internet, DO NOT DO THIS. I implore you to put the time into implementing OAuth for your API. Please. Please please please.
Take a look at this: http://toys.lerdorf.com/archives/55-Writing-an-OAuth-Provider-Service.html
Do not use a password for API clearance, even if it is encoded, especially if it is encoded in MD5. Furthermore I would not use the users username as well. Let the user generate a key. You are giving someone the ability to know 50% of what they need to know to access a user's account, and MD5 has a lot of sites that you can reverse it and find a password match. A key is certainly the best way to go so a developer could regenerate it further down the road for security purposes. Always think of security.
How about signing requests using HMAC_SHA1 and the user's password? For example, your URL: http://domain.com/api.php?api_option=list&api_user_name=USERNAME&api_user_password=PASSWORD
Add the timestamp and/or a random string (nonce) and build a normalized base_string:
$base_string = "api_option=list&api_user_name=USERNAME×tamp=1296875073&nonce=hgg65JHFj";
$signature = hmac_sha1($base_string, PASSWORD);
then the new URL would be:
http://domain.com/api.php?api_option=list&api_user_name=USERNAME×tamp=1296875073&nonce=hgg65JHFj&signature=kfvyhgfytgyr6576yfgu
What your server does is to get all the options, excluding the signature, then generate the signature using the same method and compare it to the signature sent by the client, which should be the same.
first of all,
You don't need to send the user's login credentials using the GET method.
You probably want to do that using the POST method so it can be hidden from the url.
then in your api backend, You can get it like this
$username = $_POST['username'];
$password = $_POST['password'];
Still though, what you've done so far is not any guarantee that you API is safe .
In order to provide a much more safer method, You probably want to assign AUTHENTICATION TOKEN to each user .
PS: dont know if this helps anyone lol
Related
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.
I'm creating my first API in PHP for a demo, so it's not going to be used in real world. As a part of my demo I need user registration and authorization. As this is a demo I don't need much security but I don't want just to pass the users credentials in the request url either.
I like the solution suggested in the answer to this question Building Secure Public API with PHP/MYSQL. But it's unclear how we should pass the password to the server when the user is registering for the first time and what we should store on the server (e.g. the password itself?)
Also if anyone could just suggest anything else, I'd appreciate it. I'm completely new to this and a little confused after having read a lot of articles on the topic for the last few days.
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.
I have a server with mysql information stored on it. Now i need my Iphone application to be able to log in to a account and update information stored in the the database. So i was wondering, what would be the best way to go about this?
Shall i just use POST to send data to a PHP script and then echo a response for wether the user can login or not(The username and password match) ?
It's just this seems unsecure, also do i need to create some kind of session once the log in stage has been completed?
I have never done this before, so would be really grateful of any help!
Thanks very much
You described the common way to do it. You need some sort of a webserivce you can "talk" with. It's done in the way you post the data to the webserivce, the webserivce (e.g. written in PHP) opens a connection to the database and returns wether the request/login was successful.
If you just send the password in clear text, than it's unsecure you are right. I use two things to make the communication more secure.
SSL: If possible make a secure connections. But it's possible that you do not have the option to connect through ssl.
Password hashing: You can at least hash the password. In a normal case the username is public in an application, but the password isn't. A hashing function is function that returns a string that looks a little bit random to humans. Hash functions are one way functions. There's no way to go back to the original string (if you don't have a few super computers and a few hundred years of time). So once you retrieved a hashed password within your webservice, just hash the password in the database too and compare them. A string always returns the same hash if you use the same hash function. Common hash functions are: MD5 or the SHA familiy
I hope my answer helps you any further. Perhaps my approach is not the most secure, but until know no one told me anything better. ;-)
For phone apps, desktop app and some web apps this is a common issue.
Sandro Meier (above) said correctly that if you have SSL access then this is best way to send via a HTTP POST a username and password so anyone else on the network cannot sniff these details.
If you cannot use HTTPS, then I would recommend from your iPhone app.
1. post username + password to the PHP from the iPhone.
2. ON the server in PHP code, check these details, if correct generate some random token eg (KHnkjhasldjfoi&*) you can do this by using the MD5 hash function in PHP.
3. Save this hash in the db so you know which user you sent it back to.
4. Now for all other requests from the app to the PHP include this token with the request (in PHP you will need to check this token and if it is valid, then fetch or update data).
5. This way if someone is trying to sniff the connection they dont have access to the users password, they can only steal the token.
If you want to be 99% secure you need to use a HTTPS connection (but HTTPS can be faked, I wrote about this in Computer World).
The pervious person mentioned using a MD5 hash to send the username password, but this also can be hacked (a user could download you app, find the salt to the MD5 hash and that way they could still steal any password). I think the W3C said that they do not recommend encrypting web forms and password pages as it gives a false sense of security because pretty much anything can be decrypted (I think a Quantum computer can even decrypt HTTPs), they recommend using HTTPs as it provides the most security for sending sensitive data.
W3C Passwords in the clear.
http://www.w3.org/2001/tag/doc/passwordsInTheClear-52
I'm asked to write a Web API for an application (pc executable, not web-app) that will allow sending emails.
A user clicks something, the app communicates with the API which generates an email and sends it out.
I have to make sure noone unauthorised will have access to the API, so I need to make some kind of authentication and I haven't got an idea how to do it correctly.
There will be more applications accessing the API.
First thought was - send username and password, but this doesn't solve the problem really. Because if someone decompiles the application, they'll have the request url and variables including user/password or simply it can just be sniffed.
so... what options do I have?
I'm fairly sure secure connection (SSL) is not available to me at the moment, but still, this won't help me against the decompiling problem, will it?
EDIT
I haven't said that initially, but the user will not be asked for the username/password. It's the application(s) that will have to be authenticated, not users of the application(s).
The distribution of your software is really the crux of the problem. Hashing user names and passwords and storing them in the software isn't any more useful than storing un-hashed values, as either one would work to access the API server. If you're going to implement usernames and passwords for your users, I think you can use that as a pre-cursor to API control without storing the values in the software itself. Let me describe this in two parts.
Request Signatures
The most common method in use for API request verification is request signatures. Basically, before a request is sent to an API server, the parameters in the request are sorted, and a unique key is added to the mix. The whole lot is then used to produce a hash, which is appended to the request. For example:
public static function generateRequestString(array $params, $secretKey)
{
$params['signature'] = self::generateSignature($params, $secretKey);
return http_build_query($params,'','&');
}
public static function generateSignature($secretKey, array $params)
{
$reqString = $secretKey;
ksort($params);
foreach($params as $k => $v)
{
$reqString .= $k . $v;
}
return md5($reqString);
}
You could create an API request query string using the above code simply by calling the generateRequestString() method with an array of all the parameters you wanted to send. The secret key is something that is provided uniquely to each user of the API. Generally you pass in your user id to the API server along with the signature, and the API server uses your id to fetch your secret key from the local database and verify the request in the same way that you built it. Assuming that the key and user id are correct, that user should be the only one able to generate the correct signature. Note that the key is never passed in the API request.
Unfortunately, this requires every user to have a unique key, which is a problem for your desktop app. Which leads me to step two.
Temporal Keys
So you can't distribute keys with the application because it can be decompiled, and the keys would get out. To counter-act that, you could make very short-lived keys.
Assuming that you've implemented a part of the desktop app that asks users for their username and password, you can have the application perform an authentication request to your server. On a successful authentication, you could return a temporal key with the response, which the desktop app could then store for the lifetime of the authorized session, and use for API requests. Because you mentioned that you can't use SSL, this initial authentication is the most vulnerable part, and you have to live with some limitations.
The article Andy E suggested is a good approach (I voted it up). It's basically a handshake to establish a short-lived key that can be used to authenticate. The same key could be used for signature hashing. You could also take your chances and just send the username/password unencrypted and get a temporal key (it would only happen once), but you'd have to be aware that it could be sniffed.
Summary
If you can establish a temporal session key, you won't have to store anything in the client program that can be decompiled. A username/password sent once to your server should be enough to establish that. Once you have that key, you can use it to create requests in the desktop apps, and verify requests on the API server.
I would recommend you check out OAuth. it should definitely help you out in sorting out the security issues with authorizing tools to access your API.
http://oauth.net
Someone is always going to be able to decompile and hunt for the variables. An obfuscator might be able to hide them a little better. Sniffing is also easy without SSL unless you use a private and public keyset to encrypt the request data client side and decrypt server side (but obviously this key will be stored in the client application).
The best thing to do is provide as many layers of protection as you think you will need, creating a secure connection and obfuscating your code. You could look at the following article, which demonstrates a secure connection without using SSL:
http://www.codeproject.com/KB/security/SecureStream.aspx
As mattjames mentioned, you should never store passwords in plain text format. When the user enters their password into the application, store a hash of the password. The same hash should be stored on the server. That way, if the hash is seen by an interceptor they at least wouldn't see the user's original password.
You will need to use SSL if you need to prevent people from seeing the plain text password that is sent from the app over the network to the API.
For the decompilation issue, you would want to store the hash of the password in the API, not the original password. See explanation here: http://phpsec.org/articles/2005/password-hashing.html.