web-dev-qa-db-fra.com

angular4 httpclient csrf n'envoie pas de jeton x-xsrf

Dans la documentation angulaire, il est mentionné que la variable angulaire httpclient enverra automatiquement la valeur du cookie XSRF-TOKEN dans l'en-tête X-XSRF-TOKEN de la demande de publication. Lien vers la documentation

Mais il n'envoie pas l'en-tête pour moi. Voici mon code

Nodejs code pour définir le cookie

router.get('/set-csrf',function(req,res,next){
    res.setHeader('Set-Cookie', "XSRF-TOKEN=abc;Path=/; HttpOnly; SameSite=Strict");    
    res.send();
  })

J'ai utilisé le httpclient dans app.module.ts

imports: [
  HttpClientModule
]

** Le code ci-dessus est juste pour le débogage. Je n'ai pas de point de terminaison set-csrf.

Mais il n'envoie pas d'en-tête lorsque j'envoie une demande de publication. Je ne suis pas capable de déboguer.

J'ai ajouté le problème dans le répertoire github d'angular. HttpXsrfInterceptor vérifie si la requête est GET ou HEAD, ou si elle commence par http. Si true, l'ajout de l'en-tête est ignoré.

Voici le code dans Classe HttpXsrfInterceptor

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const lcUrl = req.url.toLowerCase();
    // Skip both non-mutating requests and absolute URLs.
    // Non-mutating requests don't require a token, and absolute URLs require special handling
    // anyway as the cookie set
    // on our Origin is not the same as the token expected by another Origin.
    if (req.method === 'GET' || req.method === 'HEAD' || lcUrl.startsWith('http://') ||
        lcUrl.startsWith('https://')) {
      return next.handle(req);
    }
    const token = this.tokenService.getToken();

    // Be careful not to overwrite an existing header of the same name.
    if (token !== null && !req.headers.has(this.headerName)) {
      req = req.clone({headers: req.headers.set(this.headerName, token)});
    }
    return next.handle(req);
  }

Je ne sais pas pourquoi ils ont sauté pour la partie http/s. Voici mon numéro dans github

17
netuser

Ce que vous recherchez est HttpClientXsrfModule

Veuillez en lire plus à ce sujet ici: https://angular.io/api/common/http/HttpClientXsrfModule .

Votre utilisation devrait être comme ceci:

imports: [   
 HttpClientModule,  
 HttpClientXsrfModule.withConfig({
   cookieName: 'My-Xsrf-Cookie', // this is optional
   headerName: 'My-Xsrf-Header' // this is optional
 }) 
]

De plus, si votre code cible l'API via une URL absolue, l'intercepteur CSRF par défaut ne fonctionnera pas immédiatement. Au lieu de cela, vous devez implémenter votre propre intercepteur, qui n'ignore pas les routes absolues.

@Injectable()
export class HttpXsrfInterceptor implements HttpInterceptor {

  constructor(private tokenExtractor: HttpXsrfTokenExtractor) {
  }

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

Et enfin, ajoutez-le à vos fournisseurs:

providers: [
  { provide: HTTP_INTERCEPTORS, useClass: HttpXsrfInterceptor, multi: true }
]
33
Miroslav Jonas

Je suppose que la bonne méthode est withOptions. J'ai utilisé withConfig et j'ai eu l'erreur Property 'withConfig' does not exist on type 'typeof HttpClientXsrfModule'. Il s'agit d'un problème de frappe dans la documentation. Vous devez utiliser "withOptions" à la place de HttpClientXsrfModule.withOptions({ cookieName: 'My-Xsrf-Cookie', headerName: 'My-Xsrf-Header', })

6
Manu Chadha

En utilisant la version angulaire récente, j'ai rencontré le problème suivant. Alors que le jeton est transmis au client en utilisant le nom d’en-tête 'XSRF-TOKEN', la réponse doit renvoyer le jeton sous le nom d’en-tête 'X-XSRF-TOKEN'. Voici donc une version légèrement modifiée du code de Miroslav ci-dessus qui fonctionne pour moi.

@Injectable()
export class HttpXSRFInterceptor implements HttpInterceptor {

  constructor(private tokenExtractor: HttpXsrfTokenExtractor) {
  }

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