A Guide to Angular Security and Authentication with JSON Web Tokens
Angular is a great platform for building responsive, universal Single Page Applications. All the stable releases of Angular are production ready and deployed by a large number of enterprises and users everywhere. Here, we’ll shift our focus towards the security aspects of Angular.
Web development isn’t about writing code that works, it’s also about writing code that’s foolproof and not prone to vulnerabilities. A number of common vulnerabilities for different web applications are regularly brought to light. Vulnerabilities can seep in through obsolete dependencies, bad coding practices, or irregularities in patching updates.
In this article, we’ll discuss vulnerabilities that can occur with Angular application(s) and the best ways to circumvent these vulnerabilities.
Regular Angular Updates & Vulnerable Dependencies
The Angular team is publishing releases at frequent intervals for different feature developments, bug and vulnerability fixes, security patches, etc. Software development teams are strongly suggested to keep their Angular libraries updated constantly to stay in sync with the latest available developments. If not, malicious users may be able to attack the application that is using known security vulnerabilities associated with older versions of the software.
With the sheer number of third-party library components available today, it can be a difficult task to develop applications without the use of these libraries. Libraries sometimes can have publicized vulnerabilities that can be maliciously used by attackers to input harmful data or code into applications. Some of the well-known vulnerabilities include CSRF, buffer overflows, XSS, etc.
To verify that your dependencies and components are free some of the common loopholes and exploits, you can use open source vulnerability management tools.
Here is a list of things that you can do to ensure that your code is secure.
- Always download libraries from a repository like npm or GitHub
- Use updated versions of libraries and avoid obsolete packages
- Monitor for vulnerabilities by running an npm audit or use a code analysis tool
- Regularly visit security resources like NVD (National Vulnerability Database) and CVE (Common Vulnerabilities and Exposures)
Preventing Cross-Site Scripting (XSS)
XSS allows malicious users to input client-side scripts into web pages that are accessed by regular users. This code can inflict considerable damage. For example, it’s possible to steal user data or undertake actions that impersonate the user with the intention to cause harm. You can read more about XSS on the OWASP website.
Angular Sanitization and Security Contexts
In order to systematically and effectively block XSS bugs, Angular assumes each value as an untrusted value by default. Therefore, when a value is entered into the DOM using a template via a property, style, attribute, interpolation or class binding, Angular automatically sanitizes the value and disallows untrusted values.
Here is a sample declaration in the BrowserModule:
export const BROWSER_SANITIZATION_PROVIDERS: Array<any> = [
{provide: Sanitizer, useExisting: DomSanitizer},
{provide: DomSanitizer, useClass: DomSanitizerImpl},
];
@NgModule({
providers: [
BROWSER_SANITIZATION_PROVIDERS
...
],
exports: [CommonModule, ApplicationModule]
})
export class BrowserModule {}
The idea behind the DomSanitizer is to sanitize the input and to clean up user-submitted data. Here is an example of the of what the skeleton of the class might look like:
export enum SecurityContext { NONE, HTML, STYLE, SCRIPT, URL, RESOURCE_URL }
export abstract class DomSanitizer implements Sanitizer {
abstract sanitize(context: SecurityContext, value: SafeValue|string|null): string|null;
abstract bypassSecurityTrustHtml(value: string): SafeHtml;
abstract bypassSecurityTrustStyle(value: string): SafeStyle;
abstract bypassSecurityTrustScript(value: string): SafeScript;
abstract bypassSecurityTrustUrl(value: string): SafeUrl;
abstract bypassSecurityTrustResourceUrl(value: string): SafeResourceUrl;
As you would have noticed, there are two distinct patterns. There first is the sanitize method. This identifies the ‘context’ as well as the ‘untrusted value’ and returns a trusted value.
The second method uses the ‘bypassSecurityTrustX’ method which captures the ‘untrusted value.’ This is based on value usage and returns the trusted object.
The Sanitize() Method
In the event that a value is trusted for a particular context, the sanitize method will expose the safe value within it and utilize it directly. If not, the value will eventually be sanitized to be rendered safe based on the security context.
Three main functions exist for sanitizing values:
The sanitizeHTML function that sanitizes untrusted HTML values by parsing them and verifying its tokens.
The sanitizeStlye function that sanitizes untrusted styles or URL values using regular expressions.
The sanitizeURL function that sanitizes untrusted URL values using regular expressions.
How to Disable Sanitization
In certain situations where it might be required to disable sanitization, users are able to work around security using a constructed value via one of bypassSecurityTrustX methods. They can bind this to the value from the relevant template.
Here is an example:
import {BrowserModule, DomSanitizer} from '@angular/platform-browser'
@Component({
selector: 'my-app',
template: `
<div [innerHtml]="html"></div>
`,
})
export class App {
constructor(private sanitizer: DomSanitizer) {
this.html = sanitizer.bypassSecurityTrustHtml('<h1>DomSanitizer</h1><script>ourSuperSafeCode()</script>') ;
}
}
Authentication in Angular using JSON Web Tokens
If you’re going to implement authentication in Angular, the best bet is to use a JWT-based authentication system. As a matter of fact, using JSON Web Tokens is the best choice if you’re implementing an authentication system in any Single Page Application (SPA). In a nutshell, JWTs are digitally signed JSON payloads, encoded in a URL-friendly string format.
The payload contained in a token defines a user session. This could mean that it contains details unique to the user like userId or emailId. In order to confirm that the token is valid, the server needs to validate the token. What this means is, the server doesn’t have to contact the database to validate the token.
The token gets invalidated when it expires, and the expiry time is defined when you create the token.
The Angular Authentication Process Outline
- When the user creates an account, the authentication server creates a new token and returns it to back to the client-side application.
- The token payload assigns something unique to the user (like a userId) and additional details that include the expiry time.
- The frontend stores this token somewhere - preferably in a cookie and appends the token into the header for all the requests it make.
- The server validates the token and if the token is valid, the user is able to access the requested resource.
- When the token expires, the server decodes and checks whether the payload matches the data in the database. If yes, a new token is generated.
For more information specific to Angular, reference this article on Angular-University.io
Content Security Policy
CSP or Content Security Policy is an additional security layer that assists in detecting and inhibiting specific types of attacks including XSS and data injection. Such attacks have a goal of data theft to the distribution of malware to website defacement.
To enable CSP, you would need to configure your web server to return the correct Content-Security-Policy HTTP header. You can find detailed steps to enable CSP on the MDN website.
Using the Offline Template Compiler or the AOT Compiler
Angular templates are theoretically executable and therefore the HTML tags, binding expressions, and attributes in templates are trusted to be safe. An attacker may be able to perform something malicious if they’re able to parse an unintended value into the template.
To prevent such breaches, users can utilize offline template compilers. This process is also known as template injection.
In case you use Angular CLI, you can easily enable AOT:
ng build --aot
ng serve -aot
Avoid Direct Use of the DOM APIs
Unfortunately, the built-in browser DOM APIs do not automatically secure the application from security vulnerabilities. As an example, ‘document’ - the node that is available through ‘ElementRef’ might contain unsafe methods.
Users should avoid interacting with the DOM through direct means and use Angular templates wherever available.
XSS Protection on Server-Side
The data validation on the client-side is usually for cosmetic purposes. Someone can try to make direct API calls to the backend with the intention of breaking something.
All data on the server-side code needs to be validated and should escape appropriately to inhibit server XSS vulnerabilities. This is largely because injecting template code in an Angular application is similar to injecting executable code directly into the application.
It is recommended that Angular templates on the server-side not be generated using a template language.
HTTP-Level Vulnerabilities
Angular comes with built-in support that can help prevent a couple of common HTTP vulnerabilities – Cross-Site Script Inclusion (XSSI) and Cross-Site Request Forgery (CSRF or XSRF).
Both of these vulnerabilities have to be inhibited mainly on the server side. However, Angular also assists helpers to make integration on the client side simpler.
Cross-Site Script Inclusion (XSSI)
XSSI, also known as a JSON vulnerability, enables an attacker’s website to access data using a JSON API. Such attacks work on older browsers by including an API URL via a <script>
tag after overriding native JavaScript object constructors.
Servers can fend off such attacks by using a prefix on all JSON responses and render them non-executable using the string ")]}',\n".
The AngularHttpClient library is able to read and strip the string ")]}',\n" from each response prior to parsing further.
Cross-Site Request Forgery (XSRF)
XSRF, also known as ‘one-click attack’ or ‘session riding’, is a website violation where unauthorized commands are sent from a web application that is trusted by a user.
In usual anti-XSRF methods, application servers transmit a random authentication token via a cookie. The receiving code reads the cookie and includes a custom request header in the token for each following request. The server then makes a comparison between the received cookie value and the request header value and rejects the request in case the values are missing or are a mismatch.
The reason this method is effective is because all browsers use the same origin policy. Only the code from the originating website can read the cookies from the site and include custom headers on request. Therefore, only a trusted user application can read the cookie and add a customized header.
Angular Security Summary
We’ve covered all the security details that you need to be aware of while building components in Angular. It’s important to take security seriously (it shouldn’t be just limited to front-end). What are your thoughts on Angular security? Let us know in the comments.
Empower your development. Build better applications. Try GrapeCity's Tools for JavaScript and .NET