【问题标题】:Next.js restrict the api to my next.js application and my mobile appNext.js 将 api 限制为我的 next.js 应用程序和我的移动应用程序
【发布时间】:2021-07-01 06:15:28
【问题描述】:

让我澄清一下我的用例:

我有一个 next.js 应用程序,它是一个用于列出房地产对象的平台。我有几个我在 next.js 应用程序中使用的 api 路由。例如:

/api/createpost -> 

从我的 next.js 应用程序的表单中获取信息并创建一个数据库条目以执行新帖子

/api/getposts -> 

从我的数据库中获取所有房地产帖子并显示它

/api/login -> 

通过检查数据库中的凭据登录用户并发送 jwt

/api/register -> 

通过从我的 next.js 应用程序的表单中获取凭据、注册用户并在我的数据库中创建条目来注册用户


现在,为了保护我的 api,我想确保检查是否存在有效的用户会话,如果有人调用其中一个 api(注册/登录 api 除外)以获得预期结果。我通过调用/api/login 路由并获得有效的用户会话来做到这一点。直到这里一切正常。像 /api/createpost 这样的 API 只有在我们有一个有效的用户会话时才能被调用。

现在我想创建一个移动应用程序,并且我想使用上面的 api 路由来在我的移动应用程序中提供完整的功能。例如,如果我想在我的移动应用程序上调用/api/createpost,它应该工作相同,我需要一个有效的用户会话。

但是我想通过在我的数据库中请求一个指向我的应用程序的密钥来限制我的 api,如果你调用 /api/createpost api 就说好的,首先我需要验证它是移动应用程序在询问。然后,移动应用将在请求中提供密钥。

我还没有尝试过,但我认为它应该可以工作。 现在大混乱:如果我们调用 /api/createpost 并且 api 想要一个有效的令牌来检查数据库,这将适用于移动应用程序,因为我们给它一个有效的令牌来检查在数据库中,如果我们从 next.js 应用程序内部调用 api,我们如何提供令牌?由于我必须在客户端进行 api 调用,因此我无法提供密钥或其他东西来验证调用是否来自我的 next.js 应用程序。

【问题讨论】:

  • 我不会将此作为答案,因为我没有足够的时间编写代码示例。我要做的是 1. 找到像 JWT 这样的身份验证方法,2. 使用中间件;当您使用 JWT 时,您可以向用户提供访问令牌,无论是在网站还是移动应用程序中,2. 您可以创建一个中间件函数来解码令牌,获取其数据,检查用户是否真的存在,(所有你想检查的)等。如果一切正常,你可以访问路由,否则你会返回一个未经授权的错误。
  • 如果这是您要找的,请告诉我。如果是这样,我可以添加更详细的解释作为答案。

标签: next.js


【解决方案1】:

如果您的应用程序是私有的

(仅供您或少数选定的人使用) 您可以通过 SSL 将私有 API 密钥随应用程序的每个请求发送到服务器并进行验证。或者,您可以将 API 限制为仅接受来自特定 IP 的请求。

如果您的应用程序是公开的

不幸的是,无法确定请求的来源,因为您的应用可以发送任何内容,攻击者可以手动发送。
想一想,如果您的应用程序试图向您的 API 发出请求,任何用户都可以在此请求发送出他/她的机器之前拦截此请求,并从不同的应用程序发送完全相同的请求在同一台机器上。

你可能会说,我可以加密请求和响应,这样攻击者就没有用了。但是这样的加密将需要一个已经商定的密钥,或者在每个会话开始时提供一个新密钥的某种方式。

  1. 如果密钥已经被约定,则应用程序必须包含它,正如您在问题中已经猜到的那样,无论您尝试如何隐藏它,攻击者都可以检索此密钥。
  2. 如果加密密钥是在每个会话开始时提供的新密钥,这几乎就是 SSL 的工作方式,您的浏览器会处理此事务。您的服务器向您的浏览器发送一个公钥来加密请求,然后服务器可以使用私钥解密该请求。在这种情况下,您又回到了同样的问题,您如何验证您向谁提供了加密密钥?什么可以阻止攻击者请求加密密钥?

您必须通过某种方式来设计不需要此限制的应用程序。 我认为您应该问的问题不是如何将您的 api 限制为某个应用,而是如何设计不需要此限制的应用。 如果您能告诉我们您为什么需要此限制,我们或许可以为您提供帮助。


更新

实际上有一种方法可以验证请求是否来自您的应用,但不是使用 api 密钥。

对于网络应用程序
您可以使用 Google 的 reCAPTCHA 在您的 /register 和 '/login' 路由上验证用户,并提供访问令牌或在验证码响应成功时启动有效的用户会话。使用 reCAPTCHA v3,您甚至可以在不打扰用户的情况下验证每个用户操作。这消除了我在上面的回答中提到的两个问题-

  1. 您不必将 api 密钥存储到应用程序/网络应用程序中。
  2. 不能欺骗请求,因为它需要在您的应用程序中进行人工用户交互。验证码验证成功将从 Google 的 reCAPTCHA 服务器而不是您的客户端应用程序到达您的 API。此通信将使用 Google 与您共享的预先调解的私有 API 密钥进行身份验证,其工作方式与您验证外部域的方式相同。

适用于 Android 应用

通过Android SafetyNet Attestation API 实现相同目的的类似方法。这会检查运行时环境并使用您的应用提供 SafetyNet API 的动态生成的随机数对响应进行签名。 请仔细阅读其文档以了解如何在使用此 API 时创建潜在的安全漏洞以及如何避免这些漏洞。

对于 iOS 应用程序
DeviceCheck 的工作方式与此类似,只是设备有效性由 Apple 服务器提供给您。

【讨论】:

  • 非常感谢您的回复。请再次检查我的问题,我试图更详细地澄清我卡在哪里。
  • 谢谢,您的编辑澄清了一点。但请帮助我理解。您的手机密钥是否已硬编码到应用程序中?它是否存储在移动设备上的外部数据库中?在这两种情况下,它都不安全,事实上,任何人都可以使用免费的反编译器反编译应用程序包并轻松提取您的密钥。
  • 为什么需要验证请求是否来自您的移动应用/next.js 应用?验证用户会话还不够吗?
  • 感谢您尝试了解我的用例。请原谅我仍然在学习很多东西,也许有时我会因为我缺乏理解而问或想一些愚蠢的事情。我已将 PostgreSQL 数据库连接到我的 next.js 应用程序,例如我在其中保存用户信息和帖子。我想在那里为“平台”或类似的东西创建一个新表。在那里我会保存一个令牌,然后验证我的移动应用程序。
  • 为什么需要验证请求是否来自您的移动应用/next.js 应用?好吧我不知道..因为每个人仍然可以获取我的 /register 和 /login api 对吗?我想将它限制在我的 next.js 应用程序和我的移动应用程序中。我不知道常见的模式,我认为那是我的问题。在过去,我看到了一个平台代码,它是一个广告平台,他们将域名和令牌作为键值对保存在数据库中,允许他们的合作伙伴网站获取 api,从而为他们提供凭证。这对我来说似乎很安全,因为只有他们被允许调用 api
【解决方案2】:

重要的修改:“安全”在这里不是正确的词!您不能仅仅因为域是您的域就判断请求来自您的应用程序。域名不是安全信息,因为它很容易被更改。请参阅下面的@Mythos cmets。


初步答案:

Web 应用程序访问的安全不是基于 API 密钥,而是基于域白名单。这就是我们实现安全性的方式,因为只有您才能访问托管您自己的应用程序的域:因此请求必须来自您拥有的应用程序。

如果您尝试一些为网络应用程序提供 API 的第三方服务,它们通常是这样工作的:它们会让您配置一组可以访问您的数据的白名单域。 如果他们为您提供 API 密钥,则此 API 密钥始终是供服务器使用的,而不是仅供客户端使用的应用程序。

因此,如果我正确理解您的问题,您将对每个请求都这样做:

  1. 检查域。如果它在白名单中,完美,你可以继续。这适用于网络应用(查找“CORS”)。
  2. 如果不是,请检查标头中的有效 API 令牌。这适用于任何可以安全存储此 API 令牌的应用程序(例如,另一台服务器,或您的场景中的移动应用程序,尽管我对移动设备的了解不足以告诉您如何存储此类密钥)

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2021-12-06
  • 2021-04-08
  • 1970-01-01
  • 2020-11-28
  • 1970-01-01
  • 2021-01-21
  • 2021-09-23
  • 2018-02-11
相关资源
最近更新 更多