【问题标题】:Securing my API to only work with my front-end确保我的 API 仅适用于我的前端
【发布时间】:2017-05-14 03:20:54
【问题描述】:

我正在构建一个节点/快递后端。我想创建一个仅适用于我的 reactjs 前端(私有 API)的 API。

想象一下,如果这是一个电子商务网站,我的用户将浏览产品,然后选择购买什么,在下单时他们可能会或可能不会登录。

确保我的 API 仅适用于我的 reactjs 前端的最佳做法是什么?

当用户决定登录或仍以访客身份登录时会发生什么?

【问题讨论】:

  • 你没用过express吗?您可以像app.get('some/route/here', authHandlerHere, requestHandlerHere); 那样链接多个处理程序,您的身份验证处理程序可以执行类似req.isAuthenticated() ? next() : res.sendStatus(401); 的操作
  • 这至少是两个问题,而且在任何情况下都过于宽泛。阅读有关 Express、PassportJS 的文档以了解路由和身份验证,并查找跨站点请求伪造保护。然后在此处发布代码,如果您无法正常工作。

标签: node.js api authentication reactjs tokenize


【解决方案1】:

应用CORS - 服务器指定允许请求您的 API 的域。

它是如何工作的?

  1. 客户端向服务器发送特殊的“预检”请求(OPTIONS 方法),询问域请求是否来自允许的域。它还询问请求方法是否 OKAY(您可以允许 GET,但拒绝 POST,...)。
  2. 服务器决定是允许还是拒绝请求。它以“OK”响应进行响应,并设置特殊的标头来告知允许哪些域/请求方法。
  3. 如果允许客户端查询您的 API,它会执行预期的请求,或者退出...

尊重 CORS 的客户端(浏览器这样做)将能够(或者如果被拒绝,则不会)能够连接。如果客户端忽略 CORS(REST 客户端、CLI 工具……),无论如何它都可以连接……

仍然需要签名请求(授权)

【讨论】:

    【解决方案2】:

    这个用例很有趣,我认为对于许多电子商务网站来说都是一个问题。我正在研究的product 实际上已经与试图在移动领域处理这类事情的公司进行了一些对话。用户登录可用于告诉您谁在使用 API,但如果您不想强迫人们拥有用户名/登录,则必须搜索替代解决方案。您似乎想要的是一种识别哪些软件正在尝试使用您的 API 的方法。

    有几种直接的方法通常用于解决这个问题:

    嵌入式秘密

    您可以向您的应用添加密钥,并要求对 API 的任何访问都使用该密钥来标识自己。人们会告诉你不要这样做,因为提取密钥真的很容易。的确如此,但在所有安全性的情况下,都需要进行成本/收益分析,以评估您想要投入多少工作来保护您的 API。 javascript 的问题在于,混淆或隐藏秘密并不容易,因为所有源代码都在那里。

    如果您正在考虑一个环境,您可以选择其他语言选择,那么您可以做更多的事情来混淆您的应用程序中的秘密(例如在 android 中使用 NDK)。不过 Javascript 很难。

    使用 API 密钥要记住的重要一点是,您永远不应该以明文形式传输它。用这种方式偷东西真的很容易。相反,您将使用密钥对 API 流量进行签名,以便服务器可以验证请求来自具有密钥并知道如何对其进行签名的东西。

    速率限制

    虽然实际上不是问题的解决方案,但取决于您要实现的目标,这是一种选择。如果您担心来自其他应用程序的大量请求,您可以将速率限制到高于正版应用程序的水平,并且如果进入的请求过多,您可以通过 IP 地址进一步阻止或速率限制。

    【讨论】:

      【解决方案3】:

      我得到了上述solution by @ThePragmatist的帮助。

      我的 React 网站上有一些基于环境的配置,例如后端 API 基本 URL(例如 staging-api.test.com、dev-api.test.com)、当前域名(例如 staging.test 。所以我遵循的过程:

      在客户端:

      • user-agent/IP/something else from the header + request timestamp + _ + random 6 digit string 创建一个字符串
      • 使用任何环境配置创建一个 JWT 令牌(我使用了 backend_api + domain + another config 之类的组合)作为密钥和在上述步骤中生成的字符串
      • 在名为token 的自定义标头中发送生成的令牌

      在服务器端验证

      • 中间件用于验证任何具有 Redis 实现的公共 API 请求,以阻止用户对新请求使用相同的令牌。
      • 验证在标头 token 中收到的 JWT 令牌。如果 JWT 可以验证,则提前处理,否则返回 403
      • 检查请求中收到的timestamp。如果时间戳为 2 分钟或更早,请使用 524(或其他根据您的需要)拒绝请求,否则继续
      • 检查令牌末尾是否有一个随机的 6 位字符串。如果不是,则拒绝请求,因为令牌格式错误
      • 检查是否存在上述token 标头值的redis-key。如果是,则意味着之前的请求中使用了相同的标头,然后只需使用 403 拒绝请求,否则继续前进
      • token 标头保存在Redis 中,expire time 的时间为 2 分钟 + 10 秒(仅缓冲 10 秒)

      这样,所有公共请求都会发送一个令牌,垃圾邮件发送者/黑客很难猜到这个令牌,因为我们使用多个配置作为私钥来签署标头。此外,他们将无法在另一个请求中使用相同的 header。只有客户端应用程序才能生成令牌,因为我们遵循了多项内容,例如标头、时间戳、最后的随机字符串(只是为了造成一些混乱)等。

      我希望它能解决某人的疑问。

      编辑

      如果我们使用有效期为 2-4 分钟的TOTP (Time-based OTP),也可以在服务器端验证随机的 6 位字符串。这将使生成的令牌更强大,因为我们将能够验证令牌的每个可能部分。

      【讨论】:

        【解决方案4】:

        从今天开始,任何用户都可以通过检查浏览器控制台中的网络选项卡来查看传递到后端的内容。确保您的 api 安全的唯一方法是通过使用 JWT 或类似方法的用户身份验证。如果您的应用程序向来宾用户开放,那么 cors 就无法真正提供帮助,因为用户所要做的就是通过 curl 或 postman 向您的 api 发出与他们在浏览器控制台中看到的相同的请求。

        【讨论】:

          【解决方案5】:

          所以,这可能是一个稍微冗长的答案 - 但您发布了一个相当有趣且重要的问题。

          作为一个花费我大部分时间在 Node 和 Python 中编写安全库来处理这类事情的人,我想我会跳到这里。

          您想要用来保护您的 React 应用程序和后端 API 的协议是 OAuth2 密码授予流程。理论上它的工作方式非常简单。

          在您的 React 应用程序上,您收集用户的用户名/密码(如果这是您构建应用程序的方式,这也可以是电子邮件/密码)。

          然后您向后端 API 发送一个 POST 请求,如下所示:

          POST api.myapp.com/oauth/token
          
          grant_type=password&username=USERNAME&password=PASSWORD
          

          确保在发布到服务器时使用 application/x-www-form-urlencoded 内容类型。

          然后,您的服务器将接受此请求,通过 OAuth2 库运行它,并生成两个令牌:访问和刷新令牌。

          在服务器端 API 上生成令牌后,您会将这些令牌存储在 cookie 中,然后由用户的浏览器存储。

          从现在开始:一切都应该是自动的。当您的 React 服务器向您的后端发出 API 请求时,浏览器将通过包含这两个令牌的 cookie 自动识别用户。

          您需要在服务器端使用 OAuth2 库,因为这将处理以下内容:

          • 生成令牌。
          • 在新的访问令牌过期时交换刷新令牌。
          • 根据令牌识别用户。
          • 如果令牌遭到破坏,则撤销令牌等。

          还有很多,但这是基本的、高级的想法。

          您会注意到:这里不涉及 API 密钥。当您使用不受信任的环境(例如:移动应用程序或客户端 javascript 应用程序)时,存储永久 API 令牌完全不安全 - 原因是它们可以很容易地从源代码中提取, 或 javascript。

          使用上面提到的流程会更安全,因为您可以获得很多保护:

          • 没有永久凭据存储在不安全的位置。
          • 短期令牌用作标识符。这些会随着时间的推移而轮换。
          • 令牌存储在 Javascript 无法访问的 cookie 中。这意味着网络曝光的风险更低。
          • 在会话期间仅交换一次密码 -- 这意味着不太敏感的信息通过网络传输的频率较低 =)

          无论如何:希望这会有所帮助!

          而且,如果您正在寻找一些工具,任何 oauth 库(服务器端)都应该可以帮助您解决这些问题。如果您正在寻找可以为您执行此操作的服务,您可能需要查看我从事的产品 (Stormpath)。这是一项付费服务​​,但会代您处理很多此类复杂问题。

          【讨论】:

          • OAuth 如何保护您的 API 不被不受您控制的域访问?
          • 它没有。然而——很多人所做的是创建应用程序 ID 并在白名单的基础上将它们分配给每个应用程序。这样,您可以拥有一种非常幼稚的“保护”形式,但只允许来自列入白名单的应用程序 ID 的请求(即使攻击者可以轻松找到此数字,它也提供了进入的障碍)。
          • 感谢您提供上述信息。这非常有用。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-06-19
          • 2020-10-15
          • 2017-02-20
          • 1970-01-01
          • 2015-12-27
          • 2019-11-11
          • 1970-01-01
          相关资源
          最近更新 更多