api - 具有独立网站和 API 服务器的同构 Web 应用程序的身份验证

标签 api security authentication oauth architecture

我开发了一个 无状态 API 在服务器上 api.com .某些 API 端点需要身份验证。

我有一个 网站 的单独服务器上website.com .当用户通过网站进行身份验证时,网站服务器需要从需要身份验证的 API 端点(例如 /tweets )检索一些数据。此数据将用于服务器响应(例如,用于呈现推文)。

服务器响应还将在浏览器中下载一些 JavaScript,随后需要从需要身份验证的 API 端点(例如 /tweets)检索(通过 XMLHttpRequests (XHR))一些数据。

这种架构代表了一个 同构 Web 应用程序 .服务器在请求时呈现整个页面,然后客户端使用 JavaScript 处理用户操作。

——

在非常基本的层面上,我可以对 website.com 和 api.com 使用 HTTP 基本身份验证。但是,浏览器会在用户首次登录 website.com 时提示用户输入凭据,并在客户端向需要身份验证的端点发出 XHR 时反复提示。

我希望用户在 website.com 上使用他们的凭据登录一次。 这类似于当前的 Twitter 网站。一旦您登录到 twitter.com,网站服务器就会将您识别为已通过身份验证,并以包含 JavaScript 下载的 HTML 页面进行响应。 JavaScript 应用程序然后(大概)向无状态 Twitter API 生成经过身份验证的 XHR。

API 在设计上是一个单独的服务器。最终 API 可以向第三方开放,尽管这不是最初的要求。

我怎样才能做到这一点?我正在寻找:

  • 最简单的安全解决方案
  • 使用 OAuth(如果适用)的解决方案

  • 两者都会很棒!

    最佳答案

    您描述的情况正是 OAuth 的设计目的:客户端向一台服务器授权,然后获得对另一台服务器上资源的访问权限。在您的情况下, website.com 是授权服务器, api.com 是资源服务器。简而言之,授权服务器向客户端发送一个访问 token ,然后客户端可以将其传递给资源服务器以证明他们有权访问资源。为了使其工作,资源服务器 (api.com) 需要与授权服务器 (website.com) 核对以验证 token 是否有效或提前获知 token 。因此,在客户端、授权服务器和资源服务器之间存在一个通信三角形,在其中传递共享 secret 。因此,绝对有必要在链的所有部分使用安全连接(HTTPS);否则,有人可以拦截 token 并假装是授权客户端。通过使用不能完全验证用户身份的受限访问 token ,这可以保持在合理范围内,但仍然是您应该尝试防止的问题。

    虽然理论上是安全的,但 OAuth 是一个复杂的系统,很难做到正确。有些人认为这几乎是不可能的(特别是 Eran Hammer,OAuth 2.0 规范的最初主要作者,他决定退出工作组)。但是,考虑到您无论如何都需要使用 HTTPS,您可以完全避免 OAuth,而是使用一个鲜为人知的 HTTPS(或实际上是 TLS)的内置功能,称为(惊喜!)客户端身份验证。

    您可能已经知道,在 HTTPS 协议(protocol)中,服务器 (website.com) 使用由受信任机构签署的证书来验证自己。这是一个很好理解且非常安全的机制(至少按照互联网标准),前提是证书不受损害并且使用最新版本的 TLS。客户端也可以这样做,即使用由受信任机构签署的证书进行身份验证。后者的权限可以是服务器(website.com)为此目的,因为服务器可以信任自己。所以TLS客户端认证的优雅之处在于客户端不需要联系第三方来获取证书;客户端和服务器可以合作为客户端提供服务器可以信任的证书。这甚至可能对用户非常友好,因为客户端证书只需要传输和安装一次,然后就可以用于后续 session 的身份验证,甚至可能不需要用户输入密码。相同的客户端证书也可用于与其他服务器(例如 api.com)的 HTTPS 连接,前提是这些服务器知道该证书并信任对其进行签名的机构 (website.com)。

    TLS 客户端身份验证可能比 OAuth 更安​​全,但总体上它可能需要较少的用户交互(取决于浏览器中处理客户端证书的方式)。另一方面,大多数用户可能不熟悉 TLS 客户端身份验证的特定机制。如果用户需要从许多不同的设备登录或需要对许多不同的服务器进行身份验证,则此工作流程可能会令人困惑或繁琐,因为每个设备都需要有一个证书,并且在更换新服务器时可能需要用户手动选择证书是第一次访问。

    总结一下:

  • 在这两种情况下,website.com 都为客户端提供了一种授权访问 api.com 的方法,api.com 需要了解这一点。所以 api.com 不可能是 100% 无状态的;它需要对website.com与客户端通信的授权方式有一定的了解。
  • 这两种情况都需要安全连接 (HTTPS)。
  • 在 OAuth 中,授权手段是“共享 secret ”受限访问 token (也称为“伪身份验证”),而在 TLS 客户端身份验证中,它是一个私有(private)证书,可以对客户端进行完全身份验证,因为它是由受信任的机构签署的。
  • 在 OAuth 中,授权是在数据层上完成的(应用程序明确地传达访问 token ),而在 TLS 客户端身份验证中,身份验证是在传输层上完成的(这意味着您的 API 实际上不需要知道身份验证甚至授权,如果Web 服务器配置为仅允许某些端点访问经过身份验证的客户端)。
  • TLS 客户端身份验证可能更值得信赖,但用户可能更熟悉 OAuth,因为它“照常”使用密码登录。


  • 针对评论的一些澄清:

    How does website.com know the user is logged in? How does website.com remember the user is logged in (i.e. between browser refreshes)?



    通过将访问 token 存储在客户端的安全 cookie 中。对于从客户端到 website.com 的每个请求,访问 token 都包含在请求 header 中。这样,website.com 可以确保每个请求都经过身份验证(如果请求包含访问 token ,即用户已登录),或者访问者是访客。

    How does the browser make authenticated XHR requests?



    通过在请求 header 中发送访问 token ,就像在 website.com 中一样。显然,这需要客户端可以访问 cookie。

    website.com needs to authenticate with api.com when creating the server response



    当它这样做时,它只是代表用户发送一个(HTTPS)请求。访问 token 包含在请求 header 中是一样的。 website.com 在执行此操作时始终拥有用户的访问 token ,因为它要么即将提供给用户,要么刚刚从用户那里收到它。

    关于维基百科的更多信息:
  • https://en.wikipedia.org/wiki/Oauth
  • https://en.wikipedia.org/wiki/HTTP_Secure#Use_as_access_control
  • https://en.wikipedia.org/wiki/Transport%5FLayer%5FSecurity#Client-authenticated%5FTLS%5Fhandshake
  • 关于api - 具有独立网站和 API 服务器的同构 Web 应用程序的身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27136935/

    相关文章:

    asp.net-mvc - ASP.Net MVC 的 AntiForgeryToken 方法是否适用于负载均衡器?

    azure - 具有安全 Azure 功能后端的静态 blazor Web 组件

    android: 二进制 XML 文件第 9 行:类 fragment 膨胀错误

    Java 类和包名称操作

    security - 安全页面上的百度 map 实现

    php - 请评论这种存储用户密码的方法...

    java - 如何实现接收文件和其他参数的 REST API

    python - 使用 Python Eve 组织 REST API Web 服务构建

    authentication - 身份服务器如何在 API 或我们使用 Authorize 属性时验证 token ?

    .net - 表单例份验证票 : how to keep the user logged in after the browser has been closed?