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.
Related
I have to access REST APIs that have CAS authentication. Hundreds of requests are launched via a batch on a Windows planned task.
I would like to be able to authenticate with a user and a password stored in a configuration file at each request.
How can I authenticate without going through the authentication form CAS in the background via PHP Rn using CURL?
How can I authenticate without going through the authentication form CAS in the background via PHP Rn using CURL?
The REST protocol allows one to model applications as users, programmatically acquiring service tickets to authenticate to other applications. Similar to asking for ticket-granting tickets, the following endpoint allows one to only verify the validity of provided credentials as they are extracted from the request body:
POST /cas/v1/users HTTP/1.0
username=battags&password=password
You may also specify a service parameter to verify whether the authenticated user may be allowed to access the given service. While the above example shows username and password as the provided credentials, you are practically allowed to provide multiple sets and different types of credentials provided CAS is equipped to extract and recognize those from the request body. See this for more info.
A successful response will produce a 200 OK status code along with a JSON representation of the authentication result, which may include the authentication object, authenticated principal along with any captured attributes and/or metadata fetched for the authenticated user.
Please see https://apereo.github.io/cas/6.3.x/protocol/REST-Protocol.html
About the login step at Angular 6:
If I did it as the following:
Send username and password to PHP;
Server code check user if exists;
If really exists, we will send a json array again to Angular containing username and user role
Save them in localstorage
And when user try to navigate through the app, we will check these credentials using canActivate guard service.
Do we need to use JWT too to set a token or isn't necessary ?
Its not compulsory to use JWT, If your application requires extra
mission critical security use it.
Using JWT protects data from unwanted modifications before its received by the server. The unwanted modifications may be made by someone intercepting the data or from the user itself .
JWT just sends data to server in encoded format along with signature. So, that modification become little tough or even if made, data is not accepted by server as signature validation fails.
Sample JWT data passed :
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 // header
.eyJrZXkiOiJ2YWwiLCJpYXQiOjE0MjI2MDU0NDV9 // payload
.eUiabuiKv-8PYk2AkGY4Fb5KMZeorYBLw261JPQD5lM
Sample plain/json data
{
"username": "hello",
"full_name" : "Jason Bourne"
}
Here, you can easily see and modify the data passed, and in JWT you can't.
Yes! you need, because :
The token-based authentication systems allow users to enter their username and password in order to obtain a token which allows them to fetch a specific resource - without entering their username and password at each request. Once their token has been obtained, the user can use the token to access specific resources for a set time period.
JWT (pronounced 'jot') is a token based authentication system. It is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is digitally signed using JSON Web Signature. The JWT is a self-contained token which has authentication information, expire time information, and other user defined claims digitally signed.
Source: JWT (JSON Web Tokens) Are Better Than Session Cookies
more info: JWT
introduction: this link
Implementation example: php-authorization-jwt-json-web-tokens
It is not neccessary, but may come in handy.
If you have single application working on a single webserver you could skip JWT completely and just have a cookie autentication mechanism, so that each JavaScript call to the webserver contains your authentication cookie so your backend can respond with proper user data.
JWT comes in handy though when you have more servers involved. Think of SSO service acting as a glue between multiple related sites, like StackOverflow and others. You just pass the JWT token and each server can safely assume the data was not tampered with and have immediate access to the user's identity, some basic details etc.
I have two applications:
server ( REST API Server)
node js
Express
jsonwebtokens
express-jwt
mongoose
client (Portable Front-end)
bootstrap
Angular JS
local-storage
angular-facebook
angular-jwt
Lateron, the client app will be ported for android, iphone and other platforms using phonegap. For OAuth, I am using Facebook as the provider. Now, I just realized JSON Web Tokens are the way to go for this kind of set up. My question is an architectural one rather than syntactical one - how to manage a secret key when signing the facebook access token and user id with JWT in nodejs?
So this is how the flow works in my app:
Angular client has a Login button
User Clicks the button > Facebook Auth starts
Client receives user_id and FB Access Token
Client sends[POST json body] both user_id and Access Token to Node+Express Server at 'http://server.com/auth/login'
Node Server has applied express-jwt to all routes except /auth/login with a
var expressJwt = require('express-jwt');
var jwt = require('jsonwebtoken');
app.use(expressjwt({ secret: ''}).unless({path: ['/auth/login']}));
Node server receives data from req.body, fetches all profile details from facebook using the JavascriptSDK, and signs it using
var token=expressjwt.sign({profile}, );
Node Server stores(updates, if user_id exists) the new token in db and sends it as response to client
client stores the new token it received as json data in local-storage
client uses angular-jwt to fetch profile data from the new token and automatically attach the new token in Authorization header for all requests it sends to the server
Now, my questions are:
Do I really need to store the JWT tokens in database? I am certainly not comparing the tokens in request headers with database
Do I need to generate random secret keys for security, each time a person logs in? If yes then how would that fit in both client and server?
When and where do I need to check for token expiration? and How do I refresh it?
I am kind of lost about the design flow and mechanism.
Ad 1. You do not have to store the JWT in the database. User ID can be part of the payload, therefore there's no need for it.
Ad 2. It's a common practice for the server side app to use one secret key for generating all JWT.
Ad 3. Check if token has expired on each request to your API and disallow access if the token has expired, return 401 status code. Client app should prompt user for credentials and request new JWT. If you want to avoid users re-submitting the credentials you can issue a refresh token that later can be used to generate new JWT.
JWT refresh token flow
http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/
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'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