Authentication & Authorization in Web Apps
Karan Gandhi
Posted on April 2, 2020
Most modern applications require individuals to verify their identity. Authentication is the process of verifying the identity of an individual. A user can interact with a web application using multiple actions. Access to certain actions or pages can be restricted using user levels. Authorization is the process of controlling user access via assigned roles & privileges.
In this post, we will be covering some Authentication & Authorization concepts as well as security recommendations.
Authentication
As mentioned before, authentication is the process of verifying identity. A unique identifier is associated with a user which is the username or userid. Traditionally, we use a combination of username and password to authenticate a user. The authentication logic has to be maintained locally so we will term it local authentication. Apart from local authentication, we can use OpenID, Oauth & SAML can also be used as Auth providers. Let's cover them step by step.
Local Authentication
The most common authentication technique is using a username and password.
The common flow while implementing it is:
- The user registers using an identifier like username/email/mobile;
- The application stores user credentials in the database;
- The application sends a verification email/message to validate the registration;
- Post successful registration, the user enters credentials for logging in;
- On successful authentication, the user is allowed access to specific resources;
- The user state is maintained via Sessions or JWT.
OpenID / OAuth
OpenID is an authentication protocol that allows us to authenticate users without using a local auth system. In such a scenario, a user has to be registered with an OpenID Provider and the same provider should be integrated with our authentication flow. To verify the details, we have to forward the authentication requests to the provider. On successful authentication, we receive a success message and/or profile details with which we can execute the necessary flow.
OAuth is an authorization mechanism that allows our application user access to a provider. On successful response, we receive a token with which we can access certain APIs on behalf of a user. OAuth is convenient in case your business use case requires some certain user-facing APIs like access to Google Drive or sending tweets on your behalf. Most OAuth 2.0 providers can be used for pseudo authentication. Having said that, it can get pretty complicated if you are using multiple OAuth providers to authenticate users on top of the local authentication system.
Multi-Factor Authentication
Users are generally recommended to have different passwords for different websites or use password managers to secure their identity. However, in reality, a major chunk of people reuse their passwords. This makes them vulnerable to credential sniffing (as this XKCD comic brilliantly explains). If an attacker has access to unsalted passwords from a dump of breached applications then he can use it to log in to our application.
To reduce the risk we can implement multi-factor authentication in our application. Multi-Factor authentication is when a user is authenticated using two or more factors as authentication methods. The factors are listed below.
Factor | Example |
---|---|
Something You Know | Passwords, PINs, TAN, security questions |
Something You Have | USB keys, Software tokens, certificates, email, SMS, phone calls. |
Something You Are | Biometrics(fingerprints/iris scans, Facial Recognition), typing speed, key pattern interval |
Location | Source IP ranges and geolocation |
The common second factors implemented in applications are:
- OTP via SMS / Phones
- TOTP (Time-based OTP) apps like Google Authenticator / Authy
- x.509 certificates
The location-based factor is used to implement geographical restrictions. IP addresses can be used to allow/block users from certain countries. This is common practice in streaming and banking applications. It's easier to access geographical data from a mobile phone or any GPS enabled device.
FIDO2-compliant biometric devices and USB keys can leverage WebAuthn API to handle the authentication. WebAuthn is a new browser API that makes it easier to implement a second factor for authentication.
Mobile Device User Authentication vs User Authentication
This is a somewhat newer scenario. Under most circumstances, we login to our mobile phones using our Google/iCloud accounts. As a device user, the account can store our private data, has access to multiple apps with persistent logins and is associated with multiple payment providers. There can be a case where our application user and the device user can be different.
While executing a critical transaction, we would like to associate a device owner with our application user OR we would like a device owner to authenticate the application users. In such cases, we have to add an extra layer of security. On Android, we can use biometric auth and keyguard manager. On iOS, we can use Local Authentication to verify the device user.
Authentication Libraries
Let’s take a look at common Node.JS authentication libraries.
PassportJS
PassportJS is one of the most popular auth libraries for Express. Apart from Local Authentication, Passport has support for OpenID, OAuth 1.0, SAML and OAuth 2.0.
There are around 500 providers/strategies which can be used with Passport. You can check our recent tutorial which covers Passport here.
Grant
Grant is another auth library. It has support for Express, Hapi and Koa. Like Passport, grant
supports OpenID connect OAuth 1.0a & OAuth 2.0. There are currently 180 supported providers.
Firebase Authentication
Firebase Auth has limited OAuth providers (Facebook, Github, Twitter, Google, Apple, Microsoft). However, it does provide Auth for email login, anonymous login, and phone number login.
A full authentication workflow is provided by the Firebase Auth API. Also, we can link Multiple OAuth users to a single user. Coupled with other Firebase products (Push, Database, Storage, Hosting, Crashlytics, Functions), this can be a very good fit for small projects.
Authentication through OWASP's Lens
Broken Authentication is ranked #2 in OWASP Top 10 and #4 in OWASP Mobile Top 10. From OWASP itself:
Confirmation of the user’s identity, authentication, and session management is critical to protect against authentication-related attacks.
There may be authentication weaknesses if the application:
- Permits automated attacks such as credential stuffing, where the attacker has a list of valid usernames and passwords.
- Permits brute force or other automated attacks.
- Permits default, weak, or well-known passwords, such as “Password1” or “admin/admin“.
- Uses weak or ineffective credential recovery and forgot-password processes, such as “knowledge-based answers”, which cannot be made safe.
- Uses plain text, encrypted, or weakly hashed passwords (see A3:2017-Sensitive Data Exposure).
- Has missing or ineffective multi-factor authentication.
- Exposes Session IDs in the URL (e.g., URL rewriting).
- Does not rotate Session IDs after successful login.
- Does not properly invalidate Session IDs. User sessions or authentication tokens (particularly single sign-on (SSO) tokens) >* aren’t properly invalidated during logout or a period of inactivity.
Taken these points into account, we can strengthen our application by:
- Hashing and salting the passwords - plaintext passwords are a huge security risk. Use libraries like
bcrypt
to implement hashes with the maximum rounds your CPU can afford (also, check this blog post for further reading on hashing algorithms); - Using password strength estimators like owasp-password-strength-test to enforce a strong password policy;
- Not truncating the passwords;
- Notifying users to update passwords regularly;
- Reauthenticating users while performing a critical transaction like payment or account update;
- Transmitting passwords over TLS (https) only;
- Not leaking any information in error messages.
Login failed. Password for user Karan is wrong
is a bad message.Login failed: Invalid user or password
is a good message.
For resetting passwords, we will take the following points into consideration:
- Send an email to the user;
- Create a temporary session for a password reset;
- Do not display user credentials on screen;
- Verify the user using security questions / TOTP codes;
- Redirect the user to a form;
- Change the password in the same session.
So far, we have covered some techniques and best practices associated with Authentication. Now, let's look at Authorization.
Authorization
Authorization is a process with which we can allow or restrict resources. Depending on the business logic, the requirement of user authorization can vary.
Let's take a CMS as an example. Blog readers can read content without authentication. To create a post in the blog, a user will have to sign up as an author. To publish a post, the user must have editor privileges. To make site-wide changes he must have Administrator privileges.
In this example, user authentication is not required to read a post but it's required to publish one.
For the sake of this example let’s define & assign some routes.
The reader role has access to /blog routes
& can read all published posts. The author role has access to /blog/posts
routes & can write a post. The editor role has access to /blog/editor
routes & can publish posts. The administrator role has access to /blog/admin
routes & can do whatever he wants.
Let's assume the business expands and there is a requirement for separate Security & JS editors.
Now, in an enhanced role:
Security Editor has access to /blog/editor
but can only publish posts marked with security
tag. JS Editor has access to /blog/editor
but can only publish posts marked with js
tag. Global Editor has access to /blog/editor
and can publish posts with all tags.
Let's expand the scenario further. A chief editor is chosen from 10 editors. One of the additional duties of the chief editor is to create reports for the authors. This action is usually assigned to administrators. The developer creates a custom action and adds the privilege to a user. The chief editor can now create reports using the /blog/reports
route.
Post registration, a user can be assigned certain roles like Author or Editor. The author role doesn't have access to /posts/editor
, so he is authenticated but not authorized. In enhanced role management, two new sub-roles were created which had authorization levels of an editor but with restriction placed with help of tags. This is roughly the basis of any authorization scenario:
- Create defined roles as per specific use cases.
- Extend or restrict certain roles depending on use cases
- Assign custom actions to a user to fine grain.
Implementing Authorized Routes (Express / Angular)
Consider a function Auth which checks user authentication.
function Auth(){
...
return auth.role;
}
We can implement Auth middleware in express using:
function checkAuth(res, req, next){
if(Auth() === 'Editor')
return next();
res.redirect('/blog')
}
app.get('/blog/editor', checkAuth, function(req, res) {
res.send('Success');
});
Angular has the CanActivate
interface which acts as a Route Guard. First, we define an AuthRouteGuard
class:
import { CanActivate } from '@angular/router';
import { Injectable } from '@angular/core';
@Injectable()
export class AuthRouteGuard implements CanActivate {
constructor() {}
canActivate() {
return this.Auth();
}
Auth(){
...
return auth.editor.status;
}
}
In Route config, we define:
import { Routes, CanActivate } from '@angular/router';
import { EditorPage } from './angular/editor-page';
import { AuthRouteGuard } from './auth-route-guard';
export const ROUTES: Routes = [
{
path: 'protected',
component: ProtectedPage,
canActivate: [AuthRouteGuard]
},
{ path: '**', redirectTo: '' }
];
When CanActivate
returns true, the user can activate the route. We have to define auth logic in the Auth() or in a separate service.
In the Express snippet, we are blocking disallowed access to a specific user role (Editor). In the Angular snippet, we have assumed a boolean editor.status
which is a custom privilege assigned to every user.
Authorization through OWASP's Lens
The most common attack associated with Authorization is privilege escalation. An example of this would be an author discovering a vulnerability and publishing Java tutorials on a JavaScript blog.
Broken Access Control in OWASP Top Ten & Insecure Authorization in OWASP Mobile Top Ten are the risks associated with Authorization.
As OWASP puts it:
Access control enforces policy such that users cannot act outside of their intended permissions. Failures typically lead to unauthorized information disclosure, modification or destruction of all data, or performing a business function outside of the limits of the user. Common access control vulnerabilities include:
- Bypassing access control checks by modifying the URL, internal application state, or the HTML page, or simply using a custom API attack tool.
- Allowing the primary key to be changed to another’s users' record, permitting viewing or editing someone else’s account.
- Elevation of privilege. Acting as a user without being logged in, or acting as an admin when logged in as a user.
- Metadata manipulation, such as replaying or tampering with a JSON Web Token (JWT) access control token or a cookie or hidden field manipulated to elevate privileges, or abusing JWT invalidation
- CORS misconfiguration allows unauthorized API access.
- Force browsing to authenticated pages as an unauthenticated user or privileged pages as a standard user. Accessing API with missing access controls for POST, PUT and DELETE.
To strengthen Authorization, we should:
- Use
Reject-All
strategy for everything except public routes. - Implement logging for all privileged actions
- Invalidate sessions & tokens after logout/timeout.
Final Thoughts
In this article, we have covered some concepts of Authentication & Authorization. Authentication is still a major security risk. OWASP features it as an A2 risk in the OWASP Top Ten Web Application Security Risks.
As a developer, it's important to invest in secure coding practices. Web attacks are growing and extra efforts have to be made to secure Web apps.
Besides the topics we covered here today, another important security practice in web apps is protecting their JavaScript source code. See our tutorials on protecting React, Angular, Vue, React Native, Ionic, and NativeScript.
Posted on April 2, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.