所有文章 > 技术杂货铺 > Angular破损的身份验证指南:示例和预防措施
Angular破损的身份验证指南:示例和预防措施

Angular破损的身份验证指南:示例和预防措施

Angular 身份验证失败指南:示例和预防措施

身份验证是任何应用程序不可或缺的功能。它也是用户进入您的产品和业务的入口点。因此,您不仅要努力使其无缝衔接,还必须确保其安全无虞。但是,开发人员可能会忽略身份验证方面的许多漏洞。

这些漏洞通常会导致您的应用程序中出现身份验证漏洞。攻击者可以轻松利用此漏洞侵入您的应用程序。因此,在这篇文章中,我将向您介绍什么是身份验证失效。我还将向您展示如何在 Angular 应用程序中防止它。

身份验证工作流程

首先,让我们快速回顾一下身份验证在应用程序中通常是如何运作的。

Angular 身份验证失败指南:示例和预防措施

在客户端,您有一个供用户填写的登录或注册表单。然后,客户端将用户的凭据发送到服务器。服务器验证凭据并为用户创建新会话。它发回身份验证令牌或会话 ID。

客户端将此 ID 或令牌存储在前端。然后,它会随客户端向服务器发出的每个请求将其发送回去。这就是服务器识别哪个用户正在发出请求以及资源是否允许传入请求的方式。

身份验证工作流程中可能存在漏洞

服务器负责生成会话 ID 或身份验证令牌。另一方面,客户端负责安全地存储它。如果泄露,此身份验证令牌或会话 ID 可能会在您的身份验证工作流程中造成漏洞。然后,攻击者可以利用它使用合法用户的帐户侵入您的应用程序。

此外,攻击者可以窃取用户的所有凭据,访问私有资源并篡改用户的数据。由于您的服务器识别出该活动来自合法用户,因此您和用户都不会对此情况感到惊慌。这可能会对您的产品、用户和业务造成很大损害。

但是在什么情况下此令牌或 ID 可能会泄露?让我们讨论一下 Angular 在服务器端和客户端上身份验证失败的几种情况。

服务器端漏洞

当用户通过注销结束会话时,服务器应删除该会话 ID 或身份验证令牌。然后,下次用户创建新会话时,服务器还应生成一个全新的会话 ID。

然而,很多时候服务器只是更新数据库中的会话标志以注销用户。因此,它会对较新的会话使用相同的会话 ID。这种做法可能会有问题。如果攻击者或第三方之前见过您的会话 ID,即使您结束会话,他们也可以使用相同的会话 ID 劫持您的帐户。

因此,服务器绝不应该对新会话使用旧的会话 ID。相反,它应该为每个新会话创建一个新的会话 ID 或身份验证令牌。此外,服务器应该为每个会话轮换会话 ID。换句话说,会话 ID 应该有一个TTL。在 TTL 过期后,应该终止或重新创建会话。这很有用,因为服务器不需要完全依赖客户端来终止会话。

现在您已经了解了一些服务器端漏洞以及如何应对它们,接下来让我们来讨论客户端漏洞。

客户端漏洞

您的大多数客户端代码都可在浏览器中使用。因此,至关重要的是,您要以某种方式构建您的系统,以便在源代码的全局变量暴露时,系统仍能保持完整。

您应该遵循的最佳做法之一是确保会话 ID 不会被任何人轻易看到或访问。首先,您不应该在前端 URL 中存储或附加身份验证令牌或会话 ID。

Angular 身份验证失败指南:示例和预防措施

您应该在前端实现会话管理,使会话 ID 远离 UI。为此,您可以将会话 ID 存储在浏览器存储中,而不是路由参数中。

让我们看看如何在 Angular 应用程序中实现上述实现。结果是我们应该对 Angular 破坏身份验证有一些防御措施。

如何在 Angular 中处理会话管理

首先,我们将创建一个带有路由的新 Angular 应用:

ng new my-app

接下来,我们将创建两个组件:主页组件和登录组件。

ng  g c home login

然后我们将为这些组件配置路由。转到app-routing.module.ts文件并添加以下内容:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { HomeComponent } from './home/home.component';
const routes: Routes = [
{ path:"", component:LoginComponent},
{ path:"home", component:HomeComponent},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

添加认证服务

接下来,我们将创建一个模拟登录 API 操作的服务。

ng g s auth

在此服务中,我们将有一个函数,它简单地向我们返回一个模拟会话 ID。auth.service.ts 文件应如下所示

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';

@Injectable({
providedIn: 'root'
})
export class AuthService {
baseURL: string = "https://random-data-api.com/api/users/random_user";

constructor(private http: HttpClient) { }

getAuthUser(): Observable<any> {
return this.http.get(this.baseURL)
}
}

我们的服务有一个getAuthUser函数,它只是向模拟 API 发出 HTTP 请求,该 API 将返回一些数据。在这些数据中,我们将获得有关用户和id属性的一些信息。出于本教程的目的,我们假设此id是用户的会话 ID。明白了吗?

创建登录页面

让我们回到我们的登录组件。在login.component.html文件中,我有一个简单的标记来呈现登录表单。

<section>
<h3>Login Page</h3>
<form>
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">Email address</label>
<input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp">
<div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
</div>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">Password</label>
<input type="password" class="form-control" id="exampleInputPassword1">
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1">
<label class="form-check-label" for="exampleCheck1">Remember Me</label>
</div>
<button (click)="login($event)" type="submit" class="btn btn-primary">Submit</button>
</form>
</section>

我在login.component.css文件中也添加了一些样式,如下所示:

section{
margin: 20px auto;
max-width: 400px;
}

section h3{
margin: 20px 0;
}

这应该使登录页面看起来如下所示:

Angular 身份验证失败指南:示例和预防措施

我使用 Bootstrap 快速将一些样式引入到我的模板中。

login.component.ts文件中,我只需从我们的Auth服务中调用getAuthUser函数并以编程方式路由到 home 组件。我还将从getAuthUser函数收到的id作为查询参数传递给 home 组件。

login.component.ts文件如下所示:

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../auth.service';
import { Router } from '@angular/router';

@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {

constructor(private AuthService:AuthService, private router: Router) { }

ngOnInit(): void {
}

login(e:any){
e.preventDefault()
this.AuthService.getAuthUser().subscribe(data=>
this.router.navigate(['/home'],{queryParams:{session_id:data.id}})
)
}

}

如果您注意到模板,当从模板单击登录按钮时,将调用上面创建的登录函数。

Home 组件

Home 组件的 HTML 文件有一个简单的模板,如下所示:

<section>
<h3>This is the home page</h3>
<p>Session ID of user: {{sessionId}}</p>
</section>

现在,我们在/home URL 中获取sessionId作为查询参数。我们将从路由中获取它并将其附加到我们组件的状态变量中。以下是home.component.ts文件应有的样子:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

sessionId:any;
constructor(private route:ActivatedRoute) { }

ngOnInit(): void {
this.route.queryParams.subscribe(params=>this.sessionId=params['session_id'])
}

}

如果您现在单击登录页面上的登录按钮,您将获得以下内容:

Angular 身份验证失败指南:示例和预防措施

问题

如您所见,URL 中的查询参数清楚地显示了用户的会话 ID。但正如我之前提到的,这不是一个好方法,可能会导致 Angular 在您的应用程序中破坏身份验证。如果用户在公共计算机上使用您的应用程序,在主页上,然后忘记注销,该怎么办?

或者,如果有人只是偷看了您的用户的计算机并看到前端 URL 上清晰可见的会话 ID,会怎么样?

使用浏览器存储

我们不必在前端路由中传递会话 ID,而是可以将其推送到浏览器存储(如本地存储或会话存储)中。

更新后的登录功能应如下所示:

 login(e:any){
e.preventDefault()
this.AuthService.getAuthUser().subscribe(data=>{
// this.router.navigate(['/home'],{queryParams:{session_id:data.id}})
localStorage.setItem('session_id',data.id);
this.router.navigateByUrl('/home')
})
}

然后,在我们的主组件中,我们可以从localStorage中获取会话 ID :

ngOnInit(): void {
//this.route.queryParams.subscribe(params=>this.sessionId=params['session_id'])
this.sessionId=localStorage.getItem('session_id')
}

现在,如果您返回/login并再次按登录按钮,您仍然应该在/home页面上看到会话 ID,但它不应该出现在您的 URL 中:

Angular 身份验证失败指南:示例和预防措施

您可以通过在 Angular 应用中使用 NgRX 的全局状态来进一步改进此实现。

创建万无一失的身份验证

我们已经了解了会话管理如何帮助您预防身份验证漏洞。但是,您可以实施预防措施来降低因 Angular 身份验证失败而遭受损害的可能性。这个想法很简单:如果您创建一个万无一失的身份验证系统,那么您已经可以预防应用程序中未来出现身份验证漏洞了!

首先,您应该在他们的系统中实现密码强度验证。核心功能将在后端实现,但如果您希望更快地交付此功能,您也可以使用这样的客户端库。

Angular 身份验证失败指南:示例和预防措施

其次,您还应该为空闲用户实现自动退出功能。这对应于用户忘记从应用程序退出以及在公共计算机上关闭应用程序窗口的用例。

您可以检测用户是否闲置了超过指定的时间,并自动向服务器发送会话终止或注销请求。这里有一个Angular,可以方便地实现这一点。

Angular 身份验证失败指南:示例和预防措施

结论

防止 Angular 身份验证失败的第一步始终是实现万无一失的身份验证。在服务器端实现这些身份验证并让 Angular 客户端在需要时与这些服务交互更安全、更好。这是因为前端检查、验证和障碍更容易绕过。

文章来源:Angular Broken Authentication Guide: Examples and Prevention

#你可能也喜欢这些API文章!