securely pass api key from remote server to authentication page - php

This is my first time building an authenticated API and I'm running into a few roadblocks.
How do I securely pass an API key from the remote client's page to my server (for the user to authenticate connecting his account to the client's page/app)?
-dylan

In my experience, API Keys are actually used as salt to hashes, and the key itself is not actually passed.
When a client generates a request to the server, it hashes a bunch of stuff together (request time, user_id) + the hash, and the hash is included in the request. On the server side, the same hash is recalculated based by retrieving the key for the server, and following the same steps. If the hash doesn't match, it means that client making requests to the server doesn't know 1) the steps to create the hash, and more importantly 2) the API key used as the salt to create the hash. In this way you can determine your client does in fact have the key, and that they know how to authenticate, all without sending the actual API Key.

Have you looked into SSL?

Related

Is my Access Token strategy a good practice or vulnerable?

I am developing API for my real-time Web Application to make it work with Mobile App.
I want make my user's data available to access/modify with Mobile App.
To avoid sending user credentials to server every time to access user data, I am going to implement Access tokens.
So what?.. Instead of storing generated Access token details like user_id, expiry_time, user_ip, etc., in database, I am going to store them in Access token itself. so, I can avoid database queries every time user requests for update.
I am thinking of following API strategy:
Initially Mobile App asks User Email and Password from user and sends request to API Server to get Access Token.
API server checks user credentials against the database table.
If user exists,
gather user_id, timestamp, user_ip, etc.,
format a comma delimited string with above data.(or url_encode?)
encrypt the comma delimited string with encryption key (I keep it safe) using Mcrypt Library.
base64_encode the encrypted data and return it as Access Token.
Mobile App stores this returned Token for later use.
Further requests from App are sent with the Token.
When access request with Token is received by API Server,
decrypts the Token with same encryption key. (So, we will get the same comma delimited string)
Parse the decrypted delimited string. we will get user_id, timestamp, user_ip.
directly use,
user_id to fetch corresponding user data.
timestamp to check if Token is expired or not.
user_ip to decide allow/deny if user IP Address change.
If encryption is failed, we can conclude it as invalid Access Token.
Advantages: No database queries required every time when user request for fresh data. so, time and resources are saved.
I didn't find any vulnerabilities / problems with this approach. that's I am here! please provide your valuable feedback!
Note: I don't know whether this is the common way in which access tokens works or not. sorry, if it is.
Do not hand reversible encryption to a user. You will need to use the same encryption key for all users, which means you have one very very secret key which you must ensure stays secret. If this key ever leaks, any user can embody any other user by recreating your token scheme and choosing arbitrary user ids. Since you're handing the cypher data to the user, they can easily mount an offline attack on it (e.g., just try any and all combinations of keys on the data until it successfully decrypts). Once the key has been discovered this way, you have no recourse besides changing the key.
Instead, use a hash which is specifically designed to slow down such brute force attacks to such a degree that they become impossible in practice. Implement this using a signed token. That means, you use the same information (user id, ip, timestamp), you add a randomly generated value, you hash all this with your secret key, and you send all these pieces except the secret key to the user.
// user_id,ip,timestamp,random_token,hash
42,127.0.0.1,12345678,oiawd8juht4mp9384,q209c8yqc23n09rhcq823n9t87q432hnq9493q784gth
The information can all be in plaintext, because it's meaningless by itself, and it's authenticated by the hash, which cannot be faked without the secret key. Use an expensive HMAC hash for this purpose.

Best way to secure Private REST API without user authentication for mobile app

I am making some Restful APIs for my mobile application.
The communication between APP and webserver has to be made in REST. These apis should be private , and only my app should able to call them for successful results.
The tough part is, there is no user id and password required in my app so i do not know how could i restrict rest API with the mobile app without basic user authentication.
One solution i thought was to embed some kind of hardcode string so when mobile app will use the restful url they will pass that in encryption format over ssl. But i know this seems like very bad solution..
kindly suggest what should be the best solution under such situation.
Take a look to the Hash-based message authentication code (HMAC) mechanism.
Wikipedia link: http://en.wikipedia.org/wiki/Hash-based_message_authentication_code
Your client (mobile app) will need a public API key that identifies the REST webservice client and a private / cryptographic key. The public API key can be send along with the HTTP request. It is public and everyone can see it. The private key, however should never be sent along with the request, and should only be known by the server and client. This key is used to generate the hashed message that instead will be sent to the server. The HMAC can be generated using a SHA1 / MD5 algorithm, a message that should be generated by an algorithm that both server and client know and, finally, the private key.
Your are right, embedded key in app can be easily retrieved by packet sniffers or various other techniques. You can overcome this issue by using following instructions.
client (your app) will call required API
server will reject it, but in response it will send a string containing random hash (=challenge).
client uses that string in combination with some other string (=password) (already embedded in app) to generate a new hash (=digest)
client will call same API again but this time using newly created digest as authentication parameters.
server will validate that digest and will proceed
FYI: the above mentioned procedure is widly accepted standard and being referred as Digest Authentication. If you need more help then just ask Google for "android http digest authentication"
You can indeed make the job harder for reverse engineers but can't make it bulletproof, as Nasir said, by introducing mathematically hard problems and transforming your hard coded string accordingly.
How about this. Suppose a number A hardcoded in app. Server sends two numbers B & P (P is a large prime). Now you can calculate the actual number that will be validated by server using (A^B) % P. Your app now encrypts the answer of (A^B)%P with Server's Public Key. Server will decrypt it with its private key, validate it and will issue a token (jwt maybe) with an expiration time. Then your app and server can communicate using that token. You can perform the calculations once when the app boots and store the token for further use.
I would suggest creating a complex token in app, made of the timestamp + appId + any other value that you can replicate on the server, and authenticate in the header of each request using those.
For example you could create a virtual "user" in your db and store in it the deviceToken and use it for your algorithm.
I personally keep one API request public, which is the timestamp getter, which returns the timestamp of the server to use within 300 seconds.
so before each request, get the timestamp, and send your created token, replicate it on the server, and thus authenticate the request.
A mediocre hacker can reverse engineer the app and replicate your tokens though

Protect from replay attacks when using request signatures in secure API communication?

I've been reading up on API communication securities and trying to figure out the best way to build a secure API. I know that OAuth and such exist, but I'm also trying to educate myself in the process and not rely on libraries.
Basically I have a Web Service and in that web service users can register for API. They will be provided a Profile ID and secret key which they have to use to build the API request from another web system.
API request is built similarly to the way banks do it, all input data sent to API has to be sorted, hash calculated and then the hash sent to the server, like this:
// Profile data
$apiProfile='api123';
$apiSecret='this-is-a-good-day-to-be-a-secret-key';
// Input
$input=array();
$input['name']='Thomas Moore';
$input['profession']='Baker';
// To ensure that the order of variables checked and received is the same on both ends:
ksort($input);
// Using serialize() for simplifying things
// http_build_query() is another option, or just placing values in order
$input['hash']=sha1(serialize($input).$apiSecret);
// Making a request to URL:
// Using file_get_contents() as an example, would use cURL otherwise
$result=file_get_contents('http://www.example.com/api.php?'.http_build_query($input));
// SERVER CALCULATES COMPARISON HASH BASED ON KNOWN SECRET KEY AND INPUT DATA
This is really good and works. But! My problem is the potential replay attack. If someone snatches this request URL, they can send it to the server again, even though they cannot change the data itself.
Now I've read some things about it that you should also either check the time or add a one-time-use token to the request, but I am unsure how exactly should I do that? Is sending a timestamp with the request really secure enough? (Receiving server would make sure that the request has originated few seconds within the time the request was made, if the clocks are somewhat in sync).
I could also add IP validations to the mix, but these can change and can be spoofed somewhat and are more of a hassle for the user.
I would love this one-time-token type of system, but I am unsure how to do this without exposing token generation to the exact same replay attack problem? (Last thing I need is allowing to give out secure tokens for middle-men).
Opinions and articles would be really welcome, I've been unable to find material that answers my specific concerns. I want to say that my API is secure, without it being just marketing speak.
Thank you!
You need to only allow token exchange via a secure channel (https), and you should have a unique hash per message. Include things like a timestamp and the ip of the client. If you don't use https, you are vulnerable to a firesheep-style attack.
Other than that, you are doing the token generation and exchange correctly.
Sending the time (and including it into the cache) is really an option.
The other option would be 2-phase algorithm when you first request for the session token or a session key, then use it for the session, and its TTL is stored on the server (which can be time or number of requests allowed)
As for the session keys idea look at schemes like http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
Example of 1-time token algorithm:
1) client composes a request for the 1-time token, signs this request with the secret key and sends it to the server.
2) server generates the key, signs it with the same key and sends it to the client (together with the signature)
3) client verifies the token using the secret key
4) client composes the request, including the token, and signs the whole request body with the secret key, then sends to the server
5) server checks whole body integrity and the token validity, then sends the response (again it can be signed with the secret key for integrity and authorship verification)

Using an API Key System

I would like to implement an API key system to secure API calls to my app.
The way I think will work is my having a private key/secret per account. Each request contains the time, account id and a hash(time+secret).
The server can then do the same thing with the users secret from the database and check that against the hash the client sent.
Is this a reasonable way to do it? It is open to a brute force attack, but I'm thinking that as long as the secret is long (ie uuid) it shouldn't be too much of a problem...
A Thought
Any one could submit another request with the same time and hash and have it accepted, after all its valid, right?
The problem being that the nonce + hash can be replayed. A real authentication protocol requires at least two messages:
Server Client
---->challenge --->
<----response------
For example, the challenge could be the nonce, supplied by the server, and the client's response would be the hash of password with the nonce.
Unfortunately, this requires state, and the whole problem with RESTful protocols is that they do not want the hassle of keeping state. And yet they want to authenticate...
So you really have three options:
Option 1: Pretend the problem does not exist, and use the stateless "authentication" protocol. This is no different from using a cookie. The nonce + password-hash is no more secure than a cookie. Cookies can be stolen, etc, and replayed. The entire web is now plagued by these replay attacks.
Option 2: Try to bolt an authentication protocol onto a stateless communication method. Here, you would have the client send you a UTC time-stamp instead of a nonce. The use of the time-stamp provides limited defense against replay. Obviously your clock is not going to be synched with that of the client, so your server will allow any timestamp within some error margin, and that error margin will be the replay margin of the authentication protocol. Note that this violates REST, because the authentication message is not idempotent. Idempotent implies "can be successfully replayed by an attacker".
Option 3: Do not try to bolt an authentication protocol onto a stateless protocol. Use SSL. Use client certificates. Instead of having the client download a string, let them generate a certificate, or you can supply them with a key-pair. They authenticate via SSL and do not authenticate in your REST layer. SSL has lots of "overhead". It is not lightweight, precisely because it does address these replay issues.
So at the end of the day, it depends on how much you value access to your APIs.
For APIs that only retrieve data (other than private data), rather than create, modify, or delete data,
option 1 in this answer
may be adequate. See, for example, the Bing Maps REST API and Google
Maps Premier web services (where here, Google Maps also hashes the URL with a digital signature
and a special key known only to the API user, which, while providing protection against modifying
the URL, apparently still doesn't provide replay attack protection).
In fact, some APIs that retrieve data do not use an API key, but rather limit access in other ways (for example, the YouTube API allows retrieving publicly available data on videos and users' channels without requiring authentication, but limits the number of recent requests).
Options 2 and/or 3 are required for APIs that do more than just retrieve publicly-available data, for instance, if it modifies user profiles, posts content, or accesses private information: see for example, the YouTube data API authentication page, where OAuth is mentioned as one possible authentication scheme.
Especially for option 1, the API key here is used in order to track access by users to your API, and most importantly, limit access by those users. Option 1 may not be appropriate for APIs that allow unlimited data access.
(This is an answer since it's too long to be a comment.)
Server contains:
username
password hash
Client sends:
username
random string
hash of (password hash + random string)
When clients calls server, server creates hash of password hash (which it knows itself) + random string (given in GET by calling client) eand evaluates if that matches the hash (given in GET by calling client)
Even better would be to create 1 function that generates a secret hash from (password hash + nonce) where "nonce" (something random) is also stored on server. Then make it possible to call the server once with username + password, which returns the secret hash; then have subsequent calls solely depend on username + random string + hash of (secret hash + random string) with the same methodology as described above, but secret being what was then password.
This way, even if your secret would be intercepted and reversed, your pass would still be safe.
And obviously, good hashing algorithms: no rot13 and even solely md5 is questionable.

Web API Security

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.

Categories