I've read about oAuth, Amazon REST API, HTTP Basic/Digest and so on but can't get it all into "single piece". This is probably the closest situation - Creating an API for mobile applications - Authentication and Authorization
I would like to built API-centric website - service. So (in the beginning) I would have an API in center and website (PHP + MySQL) would connect via cURL, Android and iPhone via their network interfaces. So 3 main clients - 3 API keys. And any other developer could also develop via API interface and they would get their own API key. API actions would be accepted/rejected based on userLevel status, if I'm an admin I can delete anything etc., all other can manipulate only their local (account) data.
First, authorization - should I use oAuth + xAuth or my some-kind-of-my-own implemenation (see http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/RESTAuthentication.html?r=9197)? As I understand, on Amazon service user is == API user (have API key). On my service I need to separate standard users/account (the one who registered on the website) and Developer Accounts (who should have their API key).
So I would firstly need to authorize the API key and then Authenticate the user itself. If I use Amazon's scheme to check developer's API keys (authorize their app), which sheme should I use for user authentication?
I read about getting a token via api.example.org/auth after (via HTTPS, HTTP Basic) posting my username and password and then forward it on every following request. How manage tokens if I'm logged in simultaneously on Android and a website? What about man-in-the-middle-attack if I'm using SSL only on first request (when username and password are transmitted) and just HTTP on every other? Isn't that a problem in this example Password protecting a REST service?
As allways, the best way to protect a key is not to transmit it.
That said, we typically use a scheme, where every "API key" has two parts: A non-secret ID (e.g. 1234) and a secret key (e.g. byte[64]).
If you give out an API key, store it (salted and hashed) in you
service's database.
If you give out user accounts (protected by password), store the
passwords (salted and hashed) in your service's database
Now when a consumer first accesses your API, to connect, have him
Send a "username" parameter ("john.doe" not secret)
Send a "APIkeyID" parameter ("1234", not secret)
and give him back
the salts from your database (In case one of the parameters is wrong,
just give back some repeatable salt - eg.
sha1(username+"notverysecret").
The timestamp of the server
The consumer should store the salt for session duration to keep things fast and smooth, and he should calculate and keep the time offset between client and server.
The consumer should now calculate the salted hashes of API key and password. This way the consumer has the exact same hashes for password and API key, as what is stored in your database, but without anything seceret ever going over the wire.
Now when a consumer subseqently accesses your API, to do real work, have him
Send a "username" parameter ("john.doe" not secret)
Send a "APIkeyID" parameter ("1234", not secret)
Send a "RequestSalt" parameter (byte[64], random, not secret)
Send a "RequestTimestamp" parameter (calculated from client time and known offset)
Send a "RequestToken" parameter (hash(passwordhash+request_salt+request_timestamp+apikeyhash))
The server should not accept timestamps more than say 2 seconds in the past, to make this safe against a replay attack.
The server can now calculate the same hash(passwordhash+request_salt+request_timestamp+apikeyhash) as the client, and be sure, that
the client knows the API key,
the client knows the correct password
Related
I am developing a RESTful API for my web and mobile applications. My intention with this API is to store all data of users so that my applications can access them easily. It is like Google's solution: you don't have a separate account for Gmail and Youtube, but a shared one.
For every request (that needs USER authentication, not only APPLICATION authentication) the following workflow is applied:
Application determines the message of the request:
MESSAGE= URL + HEADERS + BODY
Application calculates the signature of the request:
SIGNATURE= HMAC(HMAC(MESSAGE, user_password), application_key)
Application sends the request via HTTP/HTTPS:
REQUEST= MESSAGE + Signature
API recreates the signature to authenticate both user and application:
SIGNATURE= application_id/user_id HMAC(HMAC(MESSAGE, user_password_from_database), application_key)
Where e.g.:
application_id = 1
user_id = 123456
user_password= 'mypass'
user_password_from_database= '$2y$10$1234567890abcde...'
The problem with this approach is that passwords in the database are irreversibly hashed (with BCrypt), and that's why I can't use them when I want to the recreate the signature of the request.
My question is how it can be accomplished yet? Is sending user_password_from_database to the application via HTTPS a good practice? My basic workflow would be:
User logs in to the application with user_email and user_password
Application sends these credentials via HTTPS to the API
API responds with user_id and user_password_from_database if credentials are OK
From now, application can use these data to determine SIGNATURE.
From now, API can recreate SIGNATURE because user_password_from_database is the secret key, not user_password
How secure is this algorithm? Does HTTPS prevent abuse of user_password_from_database?
Footnote: the signing method detailed above is just an example, indeed I took Amazon's AWS Signature Version 4 algorithm and tried to add some user authentication to it.
I'm designing a client-server communication just for learning purposes for now.
On the server's side is php restful server and on the client's backbone js app.
The basic idea:
after successful login, server will generate unique API key, store it into DB and it will expire after some time of account inactivity
client will obtain this key and user id, save it in secure cookie and use it with every request
if keys are a match, server will process the request
all communication is on https
Is this process safe or what would you suggest?
And I really dont want to go with Oauth.
While ago, I've create a reference for API token based authorization, located here.
Something I do in one of the projects.
User signups, and API key is being generated.
User saves the API key to localstore or secured cookie.
To access API he has to exchange API key to Access Token. He sends request to endpoint and is userId and apiKey matches, HMAC-bases access token is issued.
All API requests require access token passed either by access_token query parameter or token value in cookie.
All that have to work on SSL.
I need to create a REST api to authenticate a user the first time and retrieve other information based on this user for subsequent calls. If I'm not mistaken Restful services are stateless and therefore there is no need to store user information server side. My question is how can I guarantee user authentication for all the subsequent calls without a session?
This service is needed to create an android app that can display information on mobile.
You could use OAuth which is a widely used standard.
Another option is to use BASIC authentication over SSL. Any decent HTTP library would support BASIC auth. The client will be challenged the first time the request is made. Subsequent request need to send the BASIC auth headers over a secure line.
The there is the approach where you pass a secret to your client and use HMAC-SHA256 to send a hash of the URL params over to the server. Amazon does that and there is an article that covers how this is done. It is not as complicated as OAuth.
There are many approaches available but IMO your best best is to generate a AuthToken server side and return that to the client upon successful login. Then the client includes this on every request down to the server.
What I typical do is create a MD5 hash of a secret key and the the user's id- user's username - user's password - and the current date time. Then I store the token and the current date time in the db. on look ups after that I decode the token and compare the data points against the db values and if they match the user is good. This way is stateless and easily scalable.
I'm hoping for feedback on an authentication system I have designed.
The requirements are to create a closed, single sign on web environment, where by once one of our employees visit one of our web applications, they are asked to sign in with their credentials backed by our LDAP. Once signed in, they retain this login for a set time period, or the browser session, and across all our web applications. Much how Google's web properties work with a google account, but for our internal systems.
The users themselves operate from windows, mac or linux, and some from just tablets, so this authentication environment needs to exist solely online, kerberos with mod_auth_kerb etc aren't going to cut it.
All our current web applications use PHP.
The system I have so far works like below.
There exists one central authentication system, which I will call the Authentication Handler, or "handler" for short, and one or more authentication "client" web apps, which I will call Authentication Requestor, or "requestor" for short. I will call the user and their browser just "user".
Also, for it to work, the requestor needs to be preconfigured at the handler with a unique requestor_id and return URL for that ID.
A private key for handler is generated and a public key given to all requestors before hand too.
user visits requestor
user enters URL for requestor.
no session exists for this user on requestor, so requestor creates a new SESSION_ID in PHP (with the built in session handler and session_start).
the session has no authentication, so requestor will then generate a URL to the configured handler consisting of two parts, an authrequest token and an envelope.
requestor first regenerate a new session_id (session_regenerate_id in PHP) for this auth request for the client.
requestor then generates a random password, in this case using PHP's openssl_random_pseudo_bytes and stores this in the session data
requestor then encrypts the SESSION_ID using AES256 with the random password for the authrequest in PHP using openssl_encrypt.
requestor then generates envelope data by concatenating it's unique requestor_id, a ':', and the base64-encoded random password.
requestor's envelope data is then encrypted using the pre-shared public key for the handler using openssl_public_encrypt in PHP.
requestor then sends a location: header to user that contains the encrypted envelope and the authrequest as URL parameters to handler.
handler will decrypt the envelope using it's private key, and separate the clientID and password.
handler will check the requestor_id to see if we have this configured, if not, will inform the user that the requestor was not recognised.
handler will authenticate the user (in this case, via asking for username and password and checking against LDAP and/or via a preauthenticated session)
handler will then generate a return authtoken to requestor
handler will decrypt the SESSION_ID from authrequest using the decrypted and decoded password from the envelope
handler will encrypt a new string containing SESSION_ID and an ID of the logged in credentials (username, GUID, etc) with the decrypted and decoded password from the envelope
handler then sends a location: header to user that contains the authtoken as URL parameter to a preconfigured URL for this requestor_id.
requestor receives the request, and will decrypt the token using the password in the users session.
requestor will confirm the SESSION_ID matches the users current session, else it will restart authentication.
requestor can then use the returned crednetialID to identify a local user as authenticated.
This process can be repeated across different systems to give a single signon behaviour.
So, questions:
Does anyone know of a pre-existing, standardised authentication system that meets the requirements and preforms similarly to above?
If not, and given that I'm no security expert, is there anything above that would could be broken? i.e. what is/are the weak point(s) of this method?
You could use Kerberos: http://web.mit.edu/kerberos/www/
Or you implement an internal OpenID system: http://openid.net/
There are also several PHP libraries for OpenID: http://openid.net/developers/libraries/
Your base64 encoding of the password before encryption doesn't really make any sense (for me at least), as it is a function mostly used for serializing data that is to be communicated elsewhere. However, after the envelope is encrypted, you have binary data again, so what you might want to do is serialize the ciphertext.
Also, you might want to check out whether it is possible to do hashing of the credentials at the client-side (1000 times iterated and salted MD5 or SHA-* is fine). You could check out RFC2617 (HTTP Digest Access Authentication) for inspiration. This is to counter the passwords' vulnerability while decrypted at the server.
I designed APIs in php using SLIM framework. I can access these APIs like this:
http://192.168.1.210/getSchool
This API is used to get information about schools. I am using these APIs in my android application. Now I want to make security of my these APIs. so no one can access these APIs with out authentication means no one can get list of schools by just entering the above URL in address bar.
I want that user first log in using my android application then he or she can use my api, no one can directly access in my apis.
Please give me your valuable suggestion.
Thank you in advance.
Once a user is registered with your application, you can generate & assign them an API key in the database (perhaps a hash) which you can return to the phone. Each time the phone sends a request to the API it also sends across their API key which you can validate against their database entry.
This should also all be done over SSL to avoid MITM attacks/viewing of API keys.
There are also other methods available: Looking for suggestions for building a secure REST API within Ruby on Rails (language agnostic).
You should create UID and a secret key for each user when they sign up and store on the server. And pass these to the user using https initially. The user will store these two values(make sure secret key is kept safely).
When the user want to send a api request he will create the request url then hashes it using the secret key + timestamp and addes the UID, hash and timestamp to the request and sends to the server.
The server extract the UID then gets the secret from db and then generated the hash of the request (without UID, hash and timestamp) using secret key + timestamp param.
if the hash generated and the hash param from the url matches proceed with the request or ignore it.
Or
Implement OAuth