Web 应用中身份验证和授权

2025-06-07

Web 应用中身份验证和授权

大多数现代应用程序都要求个人验证其身份。身份验证是验证个人身份的过程。用户可以使用多种操作与 Web 应用程序交互。可以使用用户级别限制对某些操作或页面的访问。授权是通过分配的角色和权限来控制用户访问的过程。

在这篇文章中,我们将介绍一些身份验证和授权概念以及安全建议。

验证

如前所述,身份验证是验证身份的过程。每个用户都有一个唯一标识符,即用户名或用户 ID。传统上,我们使用用户名和密码的组合来验证用户身份。身份验证逻辑必须在本地维护,因此我们称之为本地身份验证。除了本地身份验证之外,我们还可以使用 OpenID、Oauth 和 SAML 作为身份验证提供程序。让我们逐步介绍它们。

本地身份验证

最常见的身份验证技术是使用用户名和密码。

实现该技术的常见流程如下:

  • 用户使用用户名/电子邮件/手机等标识符进行注册;
  • 应用程序将用户凭证存储在数据库中;
  • 应用程序发送验证电子邮件/消息以验证注册;
  • 注册成功后,用户输入登录凭证;
  • 身份验证成功后,用户可以访问特定资源;
  • 用户状态通过Sessions或 JWT维护。

OpenID/OAuth

OpenID 是一种身份验证协议,它允许我们在不使用本地身份验证系统的情况下对用户进行身份验证。在这种情况下,用户必须向 OpenID 提供商注册,并且该提供商应该集成到我们的身份验证流程中。为了验证详细信息,我们必须将身份验证请求转发给提供商。身份验证成功后,我们会收到一条成功消息和/或个人资料详细信息,以便我们执行必要的流程。

OAuth 是一种授权机制,允许我们的应用程序用户访问提供程序。成功响应后,我们会收到一个令牌,我们可以使用该令牌代表用户访问某些 API。如果您的业务用例需要某些面向用户的 API(例如访问 Google Drive 或代表您发送推文),那么 OAuth 会非常方便。大多数 OAuth 2.0 提供程序都可用于伪身份验证。话虽如此,如果您使用多个 OAuth 提供程序在本地身份验证系统上对用户进行身份验证,情况可能会变得非常复杂。

多重身份验证

通常建议用户在不同网站使用不同的密码,或者使用密码管理器来保护身份安全。然而,现实生活中,很多人会重复使用密码。这使得他们容易受到凭证嗅探的攻击(正如这篇XKCD 漫画所解释的那样)。如果攻击者能够从被入侵应用程序的转储中获取未加盐的密码,那么他就可以用它来登录我们的应用程序。

谷歌调查

为了降低风险,我们可以在应用程序中实现多因素身份验证。多因素身份验证是指使用两个或多个因素作为身份验证方法对用户进行身份验证。这些因素如下所示。

因素 例子
你知道的事情 密码、PIN、TAN、安全问题
你拥有的东西 USB 密钥、软件令牌、证书、电子邮件、短信、电话。
你是某种东西 生物识别(指纹/虹膜扫描、面部识别)、打字速度、按键模式间隔
地点 源 IP 范围和地理位置

应用程序中实现的常见第二个因素是:

  • 电子邮件
  • 通过短信/电话获取一次性密码
  • TOTP(基于时间的 OTP)应用程序,例如 Google Authenticator/Authy
  • x.509 证书

基于位置的因素用于实施地理限制。IP 地址可用于允许/阻止来自特定国家/地区的用户。这在流媒体和银行应用中很常见。通过手机或任何支持 GPS 的设备访问地理数据更加方便。

符合FIDO2标准的生物识别设备和 USB 密钥可以利用WebAuthn API 来处理身份验证。WebAuthn是一种新的浏览器 API,可以更轻松地实现第二重身份验证。

移动设备用户身份验证 vs 用户身份验证

这是一个比较新的场景。在大多数情况下,我们使用 Google/iCloud 账户登录手机。作为设备用户,该账户可以存储我们的私人数据,可以访问多个应用并保持登录状态,并且与多个支付提供商关联。有时,我们的应用用户和设备用户可能不同。

在执行关键事务时,我们希望将设备所有者与应用程序用户关联,或者希望设备所有者对应用程序用户进行身份验证。在这种情况下,我们必须添加额外的安全层。在 Android 上,我们可以使用生物识别身份验证键盘锁管理器。在 iOS 上,我们可以使用本地身份验证来验证设备用户。

身份验证库

我们来看看常见的 Node.JS 身份验证库。

PassportJS

PassportJS是 Express 最受欢迎的身份验证库之一。除了本地身份验证外,Passport 还支持 OpenID、OAuth 1.0、SAML 和 OAuth 2.0。

大约有 500 个提供程序/策略可与 Passport 配合使用。您可以在此处查看我们最近介绍 Passport 的教程。

授予

Grant是另一个身份验证库。它支持 Express、Hapi 和 Koa。与 Passport 类似,grant它支持 OpenID Connect OAuth 1.0a 和 OAuth 2.0。目前支持 180 个提供商。

Firebase 身份验证

Firebase Auth 的OAuth 提供商有限(Facebook、Github、Twitter、Google、Apple、Microsoft)。但是,它确实提供了电子邮件登录、匿名登录和电话号码登录的 Auth。

Firebase Auth API 提供了完整的身份验证工作流程。此外,我们还可以将多个 OAuth 用户关联到单个用户。结合其他 Firebase 产品(推送、数据库、存储、托管、Crashlytics、函数),这非常适合小型项目。

免费试用 Jscrambler

通过 OWASP 的镜头进行身份验证

身份验证失效在OWASP Top 10中排名第 2 ,在OWASP Mobile Top 10中排名第 4。来自 OWASP 本身:

确认用户身份、身份验证和会话管理对于防止与身份验证相关的攻击至关重要。

如果应用程序出现以下情况,则可能存在身份验证弱点:

  • 允许自动攻击,例如凭证填充,攻击者拥有有效的用户名和密码列表。
  • 允许暴力攻击或其他自动攻击。
  • 允许使用默认、弱或众所周知的密码,例如“Password1”或“admin/admin”。
  • 使用弱的或无效的凭证恢复和忘记密码流程,例如“基于知识的答案”,这些流程无法保证安全。
  • 使用纯文本、加密或弱散列密码(请参阅 A3:2017-敏感数据泄露)。
  • 缺少多因素身份验证或多因素身份验证无效。
  • 在 URL 中公开会话 ID(例如,URL 重写)。
  • 成功登录后不旋转会话 ID。
  • 无法正确使会话 ID 失效。用户会话或身份验证令牌(尤其是单点登录 (SSO) 令牌)在注销或处于非活动状态时无法正确失效。

考虑到这些要点,我们可以通过以下方式加强我们的应用:

  • 对密码进行哈希和加盐处理 - 明文密码存在巨大的安全风险。请使用类似的库bcrypt来实现哈希算法,并尽可能提高 CPU 的运算轮数(此外,您还可以阅读这篇博文,了解更多关于哈希算法的信息)。
  • 使用密码强度估算器(如owasp-password-strength-test)来实施强密码策略;
  • 不截断密码;
  • 通知用户定期更新密码;
  • 在执行付款或账户更新等关键交易时重新验证用户;
  • 仅通过 TLS(https)传输密码;
  • 错误消息中没有泄露任何信息。Login failed. Password for user Karan is wrong是坏消息。Login failed: Invalid user or password是好消息。

对于重置密码,我们将考虑以下几点:

  • 向用户发送电子邮件;
  • 创建一个临时会话以重置密码;
  • 不要在屏幕上显示用户凭证;
  • 使用安全问题/TOTP 代码验证用户;
  • 将用户重定向到表单;
  • 在同一会话中更改密码。

到目前为止,我们已经介绍了一些与身份验证相关的技术和最佳实践。现在,让我们看看授权。

授权

授权是允许或限制资源的过程。根据业务逻辑,用户授权的要求可能会有所不同。

我们以一个CMS系统为例。博客读者无需身份验证即可阅读内容。要在博客中创建文章,用户必须注册为作者。要发布文章,用户必须拥有编辑权限。要进行网站范围的更改,用户必须拥有管理员权限。

在这个例子中,阅读帖子不需要用户身份验证,但发布帖子则需要。

为了这个例子,让我们定义并分配一些路线。

读者角色有权访问/blog routes并可以阅读所有已发布的帖子。作者角色有权访问/blog/posts路由并可以撰写帖子。编辑者角色有权访问/blog/editor路由并可以发布帖子。管理员角色有权访问/blog/admin路由并可以执行任何操作。

假设业务扩展并且需要单独的安全和 JS 编辑器。

现在,我们的角色变得更强大了:

安全编辑者有权访问/blog/editor但只能发布带有security标签的帖子。JS 编辑者有权访问/blog/editor但只能发布带有js标签的帖子。全局编辑者有权访问/blog/editor并可以发布带有所有标签的帖子。

让我们进一步扩展这个场景。从 10 位编辑中选出一位主编。主编的额外职责之一是为作者创建报告。此操作通常分配给管理员。开发人员创建自定义操作并将权限添加到用户。主编现在可以使用该/blog/reports路线创建报告。

用户注册后,可以分配特定角色,例如“作者”或“编辑”。“作者”角色无权访问/posts/editor,因此他已通过身份验证,但未获得授权。在增强的角色管理中,创建了两个新的子角色,它们的授权级别与“编辑”相同,但通过标签进行了限制。这大致是任何授权场景的基础:

  • 根据具体用例创建定义的角色。
  • 根据用例扩展或限制某些角色
  • 将自定义操作分配给用户以进行细粒度的操作。

实施授权路线(Express / Angular)

考虑检查用户身份验证的函数 Auth。

function Auth(){
  ...
    return auth.role; 
}
Enter fullscreen mode Exit fullscreen mode

我们可以使用以下方式在 express 中实现 Auth 中间件:

function checkAuth(res, req, next){

    if(Auth() === 'Editor')
        return next();
    res.redirect('/blog')
}
app.get('/blog/editor', checkAuth, function(req, res) {
  res.send('Success');
});
Enter fullscreen mode Exit fullscreen mode

Angular 有一个CanActivate充当路由守卫的接口。首先,我们定义一个AuthRouteGuard类:

import { CanActivate } from '@angular/router';
import { Injectable } from '@angular/core';


@Injectable()
export class AuthRouteGuard implements CanActivate {

  constructor() {}

  canActivate() {
    return this.Auth();
  }
  Auth(){
    ...
    return auth.editor.status; 
}
}
Enter fullscreen mode Exit fullscreen mode

在路由配置中,我们定义:

import { Routes, CanActivate } from '@angular/router';
import { EditorPage } from './angular/editor-page';
import { AuthRouteGuard } from './auth-route-guard';
export const ROUTES: Routes = [ 
  { 
    path: 'protected',
    component: ProtectedPage,
    canActivate: [AuthRouteGuard] 
  },
  { path: '**', redirectTo: '' }
];
Enter fullscreen mode Exit fullscreen mode

CanActivate返回 true 时,用户可以激活路由。我们必须在 Auth() 或单独的服务中定义身份验证逻辑。

在 Express 代码片段中,我们阻止了特定用户角色(编辑者)的访问。在 Angular 代码片段中,我们假设了一个布尔值editor.status,它是分配给每个用户的自定义权限。

通过 OWASP 的镜头进行授权

与授权相关的最常见攻击是权限提升。例如,作者发现漏洞后,在 JavaScript 博客上发布 Java 教程。

OWASP Top Ten中的访问控制中断OWASP Mobile Top Ten中的授权不安全是与授权相关的风险。

正如 OWASP 所说:

访问控制强制执行策略,确保用户无法超出其预期权限进行操作。访问控制失败通常会导致未经授权的信息泄露、所有数据被修改或销毁,或执行超出用户权限的业务功能。常见的访问控制漏洞包括:

  • 通过修改 URL、内部应用程序状态或 HTML 页面,或者简单地使用自定义 API 攻击工具来绕过访问控制检查。
  • 允许将主键更改为其他用户的记录,允许查看或编辑其他人的帐户。
  • 权限提升。未登录即可以普通用户身份运行,或以普通用户身份登录后以管理员身份运行。
  • 元数据操纵,例如重放或篡改 JSON Web 令牌 (JWT) 访问控制令牌、操纵 cookie 或隐藏字段以提升权限,或滥用 JWT 失效机制
  • CORS 配置错误允许未经授权的 API 访问。
  • 强制以未经身份验证的用户身份浏览经过身份验证的页面,或以标准用户身份浏览特权页面。访问 API 时缺少 POST、PUT 和 DELETE 的访问控制。

为了加强授权,我们应该:

  • 除了公共路线外,其他所有路线均应使用Reject-All策略。
  • 对所有特权操作实施日志记录
  • 注销/超时后使会话和令牌无效。

最后的想法

在本文中,我们介绍了一些身份验证和授权的概念。身份验证仍然是一个主要的安全风险。OWASP 在 OWASP十大 Web 应用程序安全风险中将其列为 A2 风险。

作为开发者,投资安全的编码实践至关重要。Web 攻击日益增多,我们必须付出更多努力来确保 Web 应用的安全。


除了我们今天讨论的主题之外,Web 应用中另一个重要的安全实践是保护其 JavaScript 源代码。请参阅我们关于保护ReactAngularVueReact NativeIonicNativeScript 的教程。

文章来源:https://dev.to/jscrambler/authentication-authorization-in-web-apps-52l6
PREV
找工作的实用清单
NEXT
不公平的技术招聘流程(高级开发人员的观点)