ARH
ARH

Reputation: 1716

ForbiddenError: invalid csrf token nodejs and Angular Ionic app

I am working on Ionic + Angular + NodeJs app to enable CSRF protection. It was working fine for sometime, but suddenly it stopped working with throwing me a message

ForbiddenError: invalid csrf token

My code is straightforward and I have banging my head since couple of days to find workaround for this, but it seems all tries failed.

Node JS server running on port 8089 (e.g) with CSRF protection

// [This is only for test purpose]
app.use(function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Methods", "*");
    res.header("Access-Control-Allow-Headers", "X-XSRF-TOKEN, Origin, X-Requested-With, Content-Type, Accept, Authorization");
    next();
  });

  app.use(bodyParser.json({limit: '20mb'})); /* {limit: "20mb"} */
  app.use(cookieParser());
  const csrfProtection = csurf({
    cookie: true,
    ignoreMethods: ['GET', 'HEAD', 'OPTIONS'],
  });

// base url is /api --> e.g (localhost:8089/api)
// it didn't worked with / only
      app.use(config.base_url, csrfProtection, (req, res, next): void => {
        res.cookie('XSRF_TOKEN', req.csrfToken(), { httpOnly: false });
        next();
      });
      // csrfProtection is not yet applied
      app.use(config.base_url, csrfProtection, HelperRouter); //post route

App Module in Ionic + Angular

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule,
    IonicModule.forRoot(),
    AppRoutingModule,
    MenuComponentModule,
    FontAwesomeIconsModule,
    HttpClientModule,
    HttpClientXsrfModule.withOptions({
      cookieName: 'XSRF-TOKEN',
      headerName: 'X-XSRF-TOKEN',
    }),
  ],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
    { provide: HTTP_INTERCEPTORS, useClass: CSRFTokenInterceptor, multi: true }
  ],
  bootstrap: [AppComponent],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}

I also tried adding HttpInterceptor // this also didn't work

@Injectable({
    providedIn: 'root'
})
export class CSRFTokenInterceptor implements HttpInterceptor {

  constructor(private tokenExtractor: HttpXsrfTokenExtractor) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const headerName = 'X-XSRF-TOKEN';
    const token = this.tokenExtractor.getToken() as string;
    console.log(token);
    if (token !== null && !req.headers.has(headerName)) {
      req = req.clone({ headers: req.headers.set(headerName, token) });
    }
    return next.handle(req);
  }
}

Also enabled proxy in Ionic + Angular app

{
    "/v0": {
      "target": "http://localhost:8089/api/",
      "secure": false,
      "logLevel" : "debug",
      "changeOrigin": true
    }
}

Response header

HTTP/1.1 403 Forbidden
x-powered-by: Express
access-control-allow-origin: *
server: nginx/1.19.0
date: Tue, 05 Jan 2021 11:38:10 GMT
content-type: text/html; charset=utf-8
content-length: 1018
connection: close
access-control-allow-methods: *
access-control-allow-headers: X-XSRF-TOKEN, Origin, X-Requested-With, Content-Type, Accept, Authorization
content-security-policy: default-src 'none'
x-content-type-options: nosniff

Request header

POST /v0/validateReferences HTTP/1.1
Host: localhost:4200
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0
Accept: application/json, text/plain, */*
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
Content-Length: 53
Origin: http://localhost:4200
Connection: keep-alive
Referer: http://localhost:4200/account/login
Cookie: _csrf=k5nvA7BbJQ9a2GvPdlpisfCQ

So what is going on

  1. The route works if I disable CSRF protection.
  2. The request goes to the correct path. /v0 (from proxy)
  3. The prefix shows the CSRF token.

I have uploaded the project in GitHub in case someone would give it a try Project link

Upvotes: 0

Views: 994

Answers (1)

ARH
ARH

Reputation: 1716

Finally, CSRF implementation is resolved. The completed implementation is in the GitHub project. GitHub

A few changes helped me to do the things first I changed the csrf get route root path

app.use('/', csrfProtection, (req, res, next): void => {
        res.cookie('XSRF_TOKEN', req.csrfToken(), { httpOnly: false });
        next();
});

Then I changed the proxy config file in ionic angular app

{
    "/api/v0/*": {
      "target": "http://localhost:8089/",
      "secure": false,
      "logLevel" : "debug",
      "changeOrigin": true
    } }

Then I changed my services to call the end points

/api/v0/validate // post route

I have added everything in the GitHub project, so if anyone faces CSRF issue, they can use the project.

Upvotes: 0

Related Questions