65.9K
CodeProject 正在变化。 阅读更多。
Home

Web 应用程序的安全身份验证:避免密码存储以缓解网络安全风险

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.43/5 (4投票s)

2023年4月10日

MIT

9分钟阅读

viewsIcon

5158

Web 应用程序中安全身份验证的重要性以及身份提供者的作用

引言

本文讨论了如何在个人项目中利用身份提供商解决方案来解决常见的安全挑战。文章概述了该方法的优点和局限性,并提供了一个演示如何使用 Next.js 实现 Spotify 认证的代码示例。该示例涵盖了使用 next-auth 库设置认证流程以及添加认证路由。

背景

我和我的朋友们组建了一支车库乐队。我们非常投入,经常排练,并且在街头表演中玩得很开心。起初,一切都很棒,我们喜欢即兴演奏不同风格的音乐并创作混搭歌曲。然而,随着我们的进步,我们遇到了一些需要解决的问题。

我们面临的主要问题之一是歌曲歌词和和弦的差异。有时,我们每个人都有不同版本的歌词或和弦,尤其是对于现场版或原声版的歌曲。此外,我们共享和更新播放列表时遇到了困难,每次更改都需要重新与整个团队共享。

为了克服这些问题,这里的 IT 人员决定创建一个软件来帮助我们的乐队以及世界各地像我们一样的乐队。然而,最大的挑战之一是确保用户安全认证。虽然大多数 Web 应用程序都需要认证,但我知道用户密码需要极其小心地处理,因为它们是黑客的常见目标。

问题

大多数 Web 应用程序,包括我的软件,都需要一个安全的认证系统来确保用户数据受到保护。虽然这是一个基本概念,但重要的是要认识到数据安全有不同的级别。总的来说,我认为两类主要数据需要不同级别的安全。

  1. 用户名和密码
  2. 其他类型的数据(“其余所有”)

需要注意的是,这种区分可能不适用于所有情况。例如,我在一家银行工作时,几乎所有数据都被视为机密并需要加密。因此,在一个简单的系统中存在多个安全级别。然而,在我歌曲软件的上下文中,我将重点关注上面提到的两类。

用户名和密码之所以需要格外关注,是因为它们是黑客的常见目标。一旦黑客使用被盗的登录凭据访问应用程序,他们就可以访问和操纵敏感数据,这可能导致严重后果。

换句话说,我对保护“其余所有”数据的能力充满信心,因为它们不太可能包含敏感内容。然而,在我数据库中存储用户密码的责任要大得多,因为 70% 的用户倾向于在多个帐户之间重复使用密码(根据 Spycloud 2021 年的一项研究)。因此,我不想为可能危及用户名和密码的数据泄露负责,这些用户名和密码可用于访问其他应用程序。

考虑以下说明

robber and front desk

一名劫匪威胁酒店接待员,要求他交出所有房间的钥匙。拿到钥匙后,劫匪进入一些房间偷走所有值钱的东西。

正如您可能已经猜到的,黑客就像劫匪一样。如果他们利用我的(或您的)应用程序中的安全漏洞,他们就可以访问敏感数据并可能攻破共享相同登录凭据的其他应用程序。

您已经知道,许多用户倾向于在多个平台之间重复使用相同的密码,这使得黑客更容易未经授权地访问他们的帐户。

解决方案

请考虑以下引言,看看您是否与我有着相同的见解

“你无法失去你从未拥有的东西” — Izaak Walton

在讨论现代技术时引用一位古老的英国作家可能显得有些奇怪,但他的话提供了一个在这种情况下可能适用的解决方案。与其存储登录和密码等敏感数据,如果我们根本不存储它们会怎样?

回到我们的示例,一个更好的安全模型将是这样

confused robber and front desk

一名劫匪威胁酒店接待员,要求他交出所有房间的钥匙。然而,接待员无法照办,因为他无法访问钥匙。相反,他向劫匪解释说,酒店有一个不同的系统,每个客人都有责任将自己的钥匙存放在更安全的地方。劫匪被建议去那里试试运气。

这正是我们想要的:不负责存储和潜在泄露任何用户密码。如果出现任何问题,那不是我们的错——毕竟,“你无法失去你从未拥有的东西”。

就软件而言,我们想要的是一个身份提供商。有很多。最常见的包括

  • Google
  • Facebook
  • Apple
  • Microsoft

您可能已经注意到,许多 Web 应用程序都提供了使用上述至少一个身份提供商登录的选项。考虑到我的应用程序用户的画像,我会说他们中的大多数都有 Spotify 帐户,无论是免费的还是付费的。毕竟,有多少与音乐相关的人(业余爱好者或不是)没有 Spotify 帐户?

因此,Spotify 是我软件选择的身份提供商。在极少数情况下,如果用户没有 Spotify 帐户,备用解决方案将是使用 Google 或 Facebook 提供商。但是,现在我想保持简单,并倾向于提示用户创建一个 Spotify 帐户,如果他们还没有的话。这样,就可以避免额外的维护和潜在问题。

此外,我打算将来使用 Spotify API 来添加与音乐相关的酷功能。

总而言之,集成认证的最简单、最安全的方法是避免自行开发。Google 和 Facebook 拥有比我们更强大的数据保护能力。

解决方案的局限性

不幸的是,这个解决方案并不完美,因为我们依赖第三方服务,有几件事可能会导致问题。主要问题包括

  1. 认证服务宕机
  2. 第三方服务安全漏洞

我们如何减轻这些问题?

  1. 认证服务宕机:多个认证提供商同时出现问题的可能性不大(例如,Google 和 Spotify 都无法工作)。因此,第一步是提示用户使用仍可用的提供商登录。但是,提前关联帐户以防止此类问题至关重要。
  2. 第三方安全漏洞:虽然第三方提供商的安全漏洞不是我们的错,但我们的软件数据会变得易受攻击。提供商可能会关闭其服务以防止进一步的问题,这可能会阻止攻击者登录我们的软件。但是,我们可以主动采取行动并禁用存在问题的认证提供商。有多种实现此目的的方法。您可能希望保留在云服务器或应用程序容器中的控制权,或者您可以让管理员用户轻松地将该提供商禁用为应用程序中的一项功能。

实现解决方案

实施此解决方案的主要目标之一是学习一种新技术或框架,以帮助加快开发过程,尤其是在用户认证方面。经过一些研究,我决定使用 Vercel 的 Next.js (React)。

为了更清楚地说明解决方案的实施方式,我将在本文中包含一些代码片段。

首先,通过运行以下命令添加 next-auth 依赖项

npm install next-auth      

安装 next-auth 后,package.json 文件将包含最新的稳定版本,在我这里是“next-auth”:“^4.19.2”。

现在创建 API 路由。导航到 pages/api/auth 文件夹并创建一个名为 [...nextauth].js 的文件(是的,包括方括号)。通过遵循此文件夹结构模式和文件名约定,NextAuth 将自动为您生成和管理各种组件,从而减少样板代码和复杂性。

以下代码代表我们身份提供商的核心实现。

import NextAuth from 'next-auth';
import SpotifyProvider from 'next-auth/providers/spotify';

export default NextAuth({
   providers: [
      SpotifyProvider({
         clientId: process.env.SPOTIFY_CLIENT_ID,
         clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
      }),
   ],
});      

如您所见,所有必需的都从一个包中导入:next-auth

import NextAuth from 'next-auth';
import SpotifyProvider from 'next-auth/providers/spotify';      

甚至 Spotify 提供商也从那里导入。顺便说一下,Spotify 使用 OAuth 2.0 授权网络。我们还需要提供一些额外的数据来将提供商与我们的应用程序关联,这可以在

clientId: process.env.SPOTIFY_CLIENT_ID,
clientSecret: process.env.SPOTIFY_CLIENT_SECRET,      

要获取 Spotify 提供商的客户端 ID 和密钥,您需要离开代码,并在 Spotify 网站上进行一些配置。以下是您需要遵循的步骤概述

  1. 如果您还没有 Spotify 开发者帐户,请注册一个。您可以在 Spotify Developer Dashboard 网站 https://developer.spotify.com/dashboard 上完成。
  2. 在仪表板上创建一个应用程序,您可以将其命名为您的软件。
  3. 配置应用程序以进行授权和用户数据访问。
  4. 从应用程序配置中检索客户端 ID 和密钥。

现在您已经获得了客户端 ID 和密钥,可以将它们添加到项目根目录下的 .env.local 文件中。该文件应位于 package.json 和其他文件所在的根目录下。

SPOTIFY_CLIENT_ID='xxxxxxxxxxxxxxxxxxxxx'
SPOTIFY_CLIENT_SECRET='xxxxxxxxxxxxxxxxxxxxx'      

如果您使用的是 Vercel,现在配置环境变量是一个好习惯

Vercel configuration

为了使会话数据可供整个应用程序使用,请将 SessionProvider 添加到 pages/_app.jsx。您的代码应如下所示

import { SessionProvider } from 'next-auth/react';

export default function MyApp = ({ Component, pageProps: 
                                 { session, ...pageProps } }) {
   return (
      <SessionProvider session={session}>
            <Component {...pageProps} />
      </SessionProvider>
   );
}

useSession React Hook 允许您检查用户是否已认证,并检索其他信息,如他们的姓名、电子邮件和头像。next-auth 提供的 signInsignOut 函数使登录和退出过程简单明了。

import { useSession, signIn, signOut } from "next-auth/react"

const { data: session, status } = useSession();

if (session) {
   {session.user.name}
   {session.user.email}
   {session.user.image}
  <button onClick={() => signOut()}>Sign out</button>
} else {
  <button onClick={() => signIn()}>Sign in</button>
}     

您只需要这些即可使身份提供商正常工作。

对于我的应用程序,我进一步创建了一个 auth 上下文和提供商来检查刚刚在 Spotify 中认证的用户是否是我应用程序的现有用户。如果是,我会检索该用户的特定数据并将他们重定向到列出他们歌曲的主页。如果不是,则会邀请用户创建帐户。

我添加的其他功能包括用于用户注册和错误处理的特定页面。您可以创建这些页面并在 [...nextauth].js 文件中进行配置。例如

pages: {
   signIn: '/auth/new-user',
   error: '/auth/error',
},      

结论

应用程序的开发取得了成功,我的朋友们喜欢使用它,并且文章开头提到的所有问题都已成功解决。然而,本文专门探讨了处理用户名和密码等敏感用户数据所涉及的风险和责任这一常见挑战。

在本文中,通过利用 Spotify、Google 和 Facebook 等身份提供商,并实现 NextAuth.js,提出了一种解决方案。通过信任现有服务并简化认证过程,可以创建一个安全高效的应用程序,也许最重要的是,通过不在我们这边存储任何用户名或密码,我们最大限度地减少了未来数据泄露的潜在后果。

如果有一天不幸发生数据泄露,我会像一个不持有钥匙的酒店接待员:“抱歉,我没有!”

历史

  • 2023年4月10日:初始版本
© . All rights reserved.