如何使用资源所有者凭据授权验证公共客户端的作用域



给定一个公共Javascript客户端希望使用资源所有者密码凭据授予类型访问API端点的情况。

一个典型的请求是这样的:

username = "john.doe@mail.com"
password = "MyP@assw0rd!"
grant_type = "password"
scope = "openid offline_access" 

没有client_id被传递,因为客户端无法存储client_secret,根据资源所有者密码凭证授予规范,它可以被省略。

授权服务器必须:

  • 要求对机密客户端进行客户端身份验证已颁发客户端凭证的客户端(或与其他身份验证需求)

问题是客户端未知时,scope = "openid offline_access"参数无法验证。在我的理解中,作用域是用来描述应用程序权限的。

问题马上就出现了。

如何验证客户端范围时,client_id被省略(有意和规范)?

一些推理:

  1. 省略client_id的原因是任何人都可以很容易地从JS客户端检索它并利用它。

  2. CORS验证在这种情况下添加的值几乎为零,因为主机头可以手工制作。

TL;DR跳到下面的结论部分…


存储在Javascript上的client_id确实可以很容易地检索到,但是这个标识符不是一个秘密,规范明确地提到了这一点。

客户端标识符不是秘密;它是公开给资源所有者的,绝对不能单独用于客户端身份验证。

(来源:RFC 6749, section 2.2)

这意味着在您的公共客户端上提供client_id是可以接受的,所以现在让我们关注第二个问题…客户端身份验证。

您引用的部分说,客户端身份验证必须要求机密客户端或任何已颁发凭据的客户端。您的应用程序不属于上述任何一种情况,因此客户端身份验证需求不适用

好的,所以您的客户端不需要(也不能实际执行)客户端身份验证。这会给您的场景带来一个问题,因为您想要验证请求的范围,所以让我们尝试找到一个兼容的解决方案…

第一件事是找到一种将client_id传递给服务器的方法,因为这是必要的。如果客户端是机密的,这将在Authorization头中与其秘密一起传递,但我们不是在那种情况下。然而,规范允许省略client_secret,所以我们仍然使用该HTTP头来传递客户端标识符。

client_secret :必需的。客户端的秘密。如果客户端秘密是一个空字符串,客户端可以省略该参数。

(来源:RFC 6749, section 2.3.1)

现在,我们在服务器端有client_id,但我们不能信任它,不根据规范,因为正如我们已经提到的,我们不能单独使用这个标识符进行客户端身份验证,即使我们尝试了一些聪明的身份验证机制(也很容易在不知道的情况下出错),也有:

授权服务器可以建立客户端认证方法公共客户。但是,授权服务器绝对不能依赖对公共客户端进行身份验证,目的是识别端。

(来源:RFC 6749, section 2.3)

该死,这是没有地方!我不能验证,所以我不能信任客户端身份所以我不能验证作用域

我明白你的意思,但还是有希望的。现在让我们关注规范的另一部分。

当客户端身份验证不可能时,授权服务器应该采用其他方法来验证客户端的身份——例如,通过要求注册客户端重定向URI 或招募资源所有者来确认身份

(来源:RFC 6749, section 10.1)

大奖!你确实在客户端身份确认过程中招募了资源所有者,他把他的用户名和密码给了客户端,这样就解决了。


结论

您似乎确实有一种方法来完成手头的任务,并且仍然声称符合规范(至少从OAuth 2.0方面)。剩下唯一要做的就是这只是我的观点,所以我还想给你一个实际实现资源所有者端点的例子。

如果你去Auth0认证API -资源所有者端点,你会发现一个具体的实现。看看别人是如何处理这个问题的总是好的。我已经注意到,这个实现选择允许在请求体本身上使用client_id,并有一些其他自定义参数作为选项,但这很好,因为OAuth 2.0没有定义严格的协议,只是定义了基础。

最后一件事,我想提醒您注意的是,offline_access作用域在OpenID Connect中用于表示您想要刷新令牌,但您不应该为公共客户端这样做。存储刷新令牌(通常是一个长期存在的凭据)几乎和存储实际密码一样糟糕。有关这类标记的一般指导,请参见刷新标记。

在这样的流中可以对每个客户端验证作用域的建议是不正确的。由于client_id是一个非秘密标识符,因此它不增加任何值。任何人都可以从Javascript实现中获取它并冒充客户端,通过网络钓鱼获取用户凭据。因此,请求的作用域只能以一种通用的、非特定于客户端的方式处理,而且:

OAuth 2.0规范建议在这种情况下不要使用资源所有者密码凭证流,https://www.rfc-editor.org/rfc/rfc6749#section-1.3.3:

凭据应该只在存在高度的资源所有者和客户端(如客户端)之间的信任是设备操作系统的一部分或具有高度特权的
应用程序),当其他授权授予类型不是
时可用(如授权码)

在浏览器内Javascript的情况下,资源所有者和客户端之间不可能有高度的信任,因为客户端不能被可靠地识别。

最新更新