Welcome to this comprehensive guide on Cross-Site Request Forgery (CSRF) in the context of Angular! Let's dive in and learn how to protect your Angular applications from this common web application security vulnerability.
Cross-Site Request Forgery (CSRF) is a type of attack that tricks the victim into unintentionally executing unwanted actions on a web application they are currently authenticated with.
š Note: CSRF attacks utilize the trust a user has in a site to perform actions on another site where the user is already authenticated.
An attacker can exploit CSRF to force authenticated users to perform actions such as changing account settings, transferring funds, or posting private messages without their knowledge or consent.
To protect your Angular applications from CSRF attacks, you can use the @ngx-security/core package, which provides built-in support for CSRF protection.
Let's set up the package and create a simple application to demonstrate CSRF protection.
npm install @ngx-security/coreor
yarn add @ngx-security/coreAppModule:import { NgxSecurityModule } from '@ngx-security/core';
@NgModule({
//...
imports: [
//...
NgxSecurityModule.forRoot()
],
//...
})
export class AppModule { }SecuredRoute interface:import { Routes, RouterModule } from '@angular/router';
import { SecuredRoute } from '@ngx-security/core';
const routes: Routes = [
{
path: 'protected',
component: ProtectedComponent,
canActivate: [SecuredRoute],
},
];SecuredRoute interface requires an authentication strategy to check if the user is authenticated before accessing the protected route.You can use the built-in TokenBasedAuthenticationStrategy for handling CSRF protection.
Now let's create a simple application with a CSRF-protected route.
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { NgxSecurityModule } from '@ngx-security/core';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
AppRoutingModule,
NgxSecurityModule.forRoot(),
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
// app-routing.module.ts
import { NgModule } from '@angular/router';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home.component';
import { ProtectedComponent } from './protected.component';
import { SecuredRoute } from '@ngx-security/core';
const routes: Routes = [
{ path: '', component: HomeComponent },
{
path: 'protected',
component: ProtectedComponent,
canActivate: [SecuredRoute],
},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
// home.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-home',
template: `
<h1>Home</h1>
<a routerLink="/protected">Go to protected</a>
`,
})
export class HomeComponent {}
// protected.component.ts
import { Component } from '@angular/core';
import { TokenBasedAuthenticationStrategy } from '@ngx-security/core';
import { AuthenticationService } from './authentication.service';
@Component({
selector: 'app-protected',
template: `
<h1>Protected Page</h1>
`,
})
export class ProtectedComponent {
constructor(private authService: AuthenticationService) {
this.authService.applyAuthenticationStrategy(
TokenBasedAuthenticationStrategy
);
}
}
// authentication.service.ts
import { Injectable } from '@angular/core';
import { TokenBasedAuthenticationStrategy } from '@ngx-security/core';
@Injectable({
providedIn: 'root',
})
export class AuthenticationService {
applyAuthenticationStrategy(strategy: any) {
TokenBasedAuthenticationStrategy.applyStrategy(strategy);
}
}Now, let's test the CSRF protection by attempting to access the protected route without including the CSRF token in the request header.
In a real-world scenario, you would typically include the CSRF token in the request header automatically when using popular Angular HTTP clients like HttpClient.
Let's create a simple form in the protected route that performs an action (e.g., changing the user's password) and requires the CSRF token.
<!-- protected.component.html -->
<h1>Protected Page</h1>
<form (ngSubmit)="submit()">
<label for="password">New Password:</label>
<input type="password" id="password" name="password" [(ngModel)]="newPassword" required>
<button type="submit">Change Password</button>
</form>// protected.component.ts (Updated)
import { Component } from '@angular/core';
import { CookieService } from 'ngx-cookie-service';
import { TokenBasedAuthenticationStrategy } from '@ngx-security/core';
import { AuthenticationService } from './authentication.service';
@Component({
selector: 'app-protected',
template: `
<h1>Protected Page</h1>
<form (ngSubmit)="submit()">
<label for="password">New Password:</label>
<input type="password" id="password" name="password" [(ngModel)]="newPassword" required>
<button type="submit">Change Password</button>
</form>
`,
})
export class ProtectedComponent {
newPassword: string;
constructor(
private cookieService: CookieService,
private authService: AuthenticationService
) {
this.authService.applyAuthenticationStrategy(
TokenBasedAuthenticationStrategy
);
}
submit() {
const csrfToken = this.cookieService.get('XSRF-TOKEN');
if (csrfToken) {
// Include the CSRF token in the request header
// ...
// Submit the form using HttpClient or other Angular HTTP client
// ...
} else {
alert('No CSRF token found, cannot change password.');
}
}
}With this example, you have now learned how to implement CSRF protection in your Angular applications, understanding its importance, and creating a practical example that demonstrates its application.
What is Cross-Site Request Forgery (CSRF)?
How does the @ngx-security/core package help protect Angular applications from CSRF attacks?