在前端存储令牌和敏感信息的安全方式(Angular 8)

Posted

技术标签:

【中文标题】在前端存储令牌和敏感信息的安全方式(Angular 8)【英文标题】:Secure Way to store Tokens and sensitives informations in front end(Angular 8) 【发布时间】:2020-01-14 01:57:41 【问题描述】:

我正在使用 Angular 8,我想使用 cookie 存储我的访问令牌和一些令牌。

所以我尝试将我的令牌存储在 cookie 中,我第一次工作,但是当我看到当我想注销并清除我的 cookie 时,它​​们并没有一直删除,并且出现 401 状态错误(未授权) 出现。我正在使用 ngx-cookie-service。您知道存储令牌的好方法和安全方法吗?这是我的 AuthService:

public login(username: string, password: string) 
    this.username = username;
    this.password = password;
    const params = new URLSearchParams();
    params.append('username', username);
    params.append('password', password);
    params.append('grant_type', 'password');
    const headers = new HttpHeaders(
      'Content-type': 'application/x-www-form-urlencoded; charset=utf-8',
      Authorization: 'Basic ' + btoa('Andricebrain:Aqwzsx1995')
    );

    const options = 
      headers
    ;
    this.httpClient
      .post(
        environment.baseUrlOauth + '/oauth/token',
        params.toString(),
        options
      )
      .subscribe(
        data => 
          this.getAuthorities(data);
          console.log(data);

          // this.router.navigate(['/home']);
        ,
        error => 
          this.toastr.error('Erreur', 'Login ou mot de passe incorrect');
        
      );
  


  getAuthorities(token): boolean 
    const headers = new HttpHeaders(
      'Content-type': 'application/json; charset=utf-8',
      Authorization: 'Basic ' + btoa('Andricebrain:Aqwzsx1995')
    );
    const options = 
      headers
    ;
    this.httpClient
      .get(
        environment.baseUrlOauth +
          '/oauth/check_token?token=' +
          token.access_token,
        options
      )
      .toPromise()
      .then(
        data => 
          console.log(token);

          this.saveToken(token, data);
          // return true;
        ,
        error => 
          console.log(error);
          alert('Error : get authorities');
          // return false;
        
      );
    return false;
  

  saveToken(token, check) 
    const expireDate = new Date().getTime() + 1000 * token.expires_in;
    this.cookie.set('access_token', token.access_token, expireDate);
    this.cookie.set('refresh_token', token.refresh_token);
    this.cookie.set('authorities', check.authorities);
    this.cookie.set('user', JSON.stringify(check.user[0]));
    this.authorities = check.authorities;
    this.user = check.user[0];
    this.router.navigate(['/home']);
  

// TokenInterceptorService

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> 
    return next.handle(req).pipe(
      tap((ev: HttpEvent<any>) => 
        if (ev instanceof HttpResponse) 
          // console.log('processing response', ev);
          // if (ev.status === 200) 
          //   this.toastr.success('L\'opération s\'est bien passée :-)', 'Succès');
          // 
          //
          // if (ev.status === 201) 
          //   this.toastr.success('Votre objet a bien été créé :-)', 'Succès');
          // 
        
      ),
      catchError((error: HttpErrorResponse) => 
        if (error.status === 401) 
          if (error.error.error === 'invalid_token') 
            // TODO: Token refreshing
            // this.toastr.info('Nous tentons de vous reconnecter !', 'Reconnexion');
            this.authService.refreshToken();

            const token = this.cookie.get('access_token');
            if (token) 
              // this.toastr.info('Reconnexion', 'Nous avons presque réussi !');
              req = req.clone(
                setHeaders: 
                  'Content-Type': 'application/json',
                  Authorization: 'Bearer ' + token
                
              );
            
           else 
            // Logout from account or do some other stuff
            this.appService.logout();
          

          if (error.error.error === 'unauthorized') 
            // TODO: Token refreshing
            // this.toastr.info('Vous ne pouvez pas accéder à cette ressource !', 'Accès Refusé');
          
        

/*
        if (error.status === 409) 
           this.toastr.error('Une donnée pose problème', 'Conflit');
         

        if (error.status === 400) 
           this.toastr.error('L\'objet qui a été envoyé est mal construit !', 'Mauvaise requête');
         
*/

        return throwError(error);
      )
    );
  

如果您能找到安全的解决方案,那就太好了

【问题讨论】:

【参考方案1】:

在浏览器中存储令牌时,一个公认的答案是使用 JWT。 它们可以被加密、签名或两者兼而有之。此外,它们在移动浏览器上的运行效果比 cookie 更好。这个库可以帮助您为您的 Angular 应用程序获得正确的 JWT 设置。 https://github.com/auth0/angular2-jwt

您对 cookie 的错误可能是由于它们未设置在正确的路径中。请记住,ngx-cookie 会将您的 cookie 设置在 URL 的当前路径上,并且您可能更愿意将它们设置在根目录。

cookieService.set( 'test', 'Hello World', 1, "/" );

鼓起勇气!

【讨论】:

以上是关于在前端存储令牌和敏感信息的安全方式(Angular 8)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 应用程序中存储机密、密钥、令牌、加密密钥等关键敏感信息

如何在 Angular 4 中处理安全会话

如何存储 Angular 前端使用的 OAuth1 令牌

在 React Native 中保存敏感数据

使用标记化有啥意义?

如何在 Angular 8 中存储 jwt 令牌之类的数据?是不是有另一种使用本地存储或会话存储安全存储的方法?