OAuth 2.0授权代码授权无秘密
OAuth 2.0 Authorization Code Grant without secret
所以我一直在考虑使用 Microsoft cordova-plugin-ms-adal plugin(使用本机库)针对使用 Azure AD 的自定义 API 为 Cordova 移动应用程序设置 OAuth 2.0。这一切都很好,但我对秘密的使用(或更具体地说,它不存在)有点困惑。
在网络上的许多文章中,他们指出在使用授权码授予和请求令牌时,您包括了秘密。当您可以安全地存储秘密时,这种授权类型非常适合使用,例如在服务器上。
然而插件不要求在应用程序中指定秘密(这是正确的)但它仍然使用授权码授予进行身份验证。我也可以手动调用
https://login.windows.net/common/oauth2/authorize?resource=http://***.onmicrosoft.com/***API&client_id=***&response_type=code&redirect_uri=http://***.onmicrosoft.com/***App
在我的浏览器中,登录,获取代码,然后 POST 使用
到 https://login.windows.net/common/oauth2/token
grant_type: authorization_code
client_id: ***
code: ***
redirect_uri: http://***.onmicrosoft.com/***App
resource: http://***.onmicrosoft.com/***API
它有效,所以我得到了一个有效的 JWT,无需发送秘密。
为什么!?这不太安全吗? (我还注意到 OAuth 2.0 spec section 4.1.3 没有说明授权类型授权码需要秘密!?)
在没有秘密/基本身份验证的情况下使用 authorization_code 授权类型有什么影响 header?
without having to send a secret.
不正确。在 link you posted 中,请求还包括:
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
也许你没有注意到。这显示 client_secret
使用 HTTP 基本身份验证以编码形式传输。
由服务器决定客户端如何进行身份验证(如果需要)。来自规范:
If the client type is confidential or the client was issued client
credentials (or assigned other authentication requirements), the
client MUST authenticate with the authorization server as described
in Section 3.2.1.
第 3.2.1 节指向第 2.3 节(严肃地说),其中说:
Clients in possession of a client password MAY use the HTTP Basic
authentication scheme as defined in [RFC2617] to authenticate with
the authorization server.
客户端密码也就是客户端密码。
所以正在传输秘密。
对所谓的机密客户端(具有客户端机密的客户端)使用授权码授予确实比使用 public 客户端更安全。
这是因为授权代码本身的交换作为 URL 参数在前端通道中发生,即通过浏览器,因此相对容易受到跨脚本、点击劫持等攻击,network/DNS 操纵等。这意味着专门的攻击者有可能在某些情况下(草率的用户、攻击者网络控制、草率的服务器实现中的重定向 URI 匹配等)窃取用户的授权码。
要用访问令牌交换授权代码,机密客户端必须在授权代码旁边的 HTTPS 保护调用中出示客户端机密,而 public 客户端没有任何方法确保它确实是指定的客户端。
这意味着攻击者模仿 public 客户端 相对 容易,因为这只需要非秘密信息(他可以获取 client_id
和来自他自己浏览器的 redirect_uri
)以及他可以通过上述攻击获取的授权 code
。
虽然获取机密客户端的授权代码的工作方式相同,但攻击者无法使用它并将其交换为访问令牌,因为为此他需要一个通常更难获得的客户端密码对于攻击者。秘密通常存储在后端存储的服务器上,并且仅通过安全的 HTTPs 通道进行通信,因此不会泄露。
将 grant_type=authorization_code
(或任何其他流程)与 public 客户端(没有秘密或以任何其他方式进行身份验证的客户端)一起使用的含义是授予的访问令牌确实不代表客户端直接访问资源的授权,它代表客户端代表用户访问资源的授权。
这就是为什么您会在 Azure AD 中注意到,当您注册本机客户端应用程序(public 客户端)时,您只能将其配置为对资源具有委派权限,而不是仅限应用程序权限。
所以我一直在考虑使用 Microsoft cordova-plugin-ms-adal plugin(使用本机库)针对使用 Azure AD 的自定义 API 为 Cordova 移动应用程序设置 OAuth 2.0。这一切都很好,但我对秘密的使用(或更具体地说,它不存在)有点困惑。
在网络上的许多文章中,他们指出在使用授权码授予和请求令牌时,您包括了秘密。当您可以安全地存储秘密时,这种授权类型非常适合使用,例如在服务器上。
然而插件不要求在应用程序中指定秘密(这是正确的)但它仍然使用授权码授予进行身份验证。我也可以手动调用
https://login.windows.net/common/oauth2/authorize?resource=http://***.onmicrosoft.com/***API&client_id=***&response_type=code&redirect_uri=http://***.onmicrosoft.com/***App
在我的浏览器中,登录,获取代码,然后 POST 使用
到 https://login.windows.net/common/oauth2/tokengrant_type: authorization_code
client_id: ***
code: ***
redirect_uri: http://***.onmicrosoft.com/***App
resource: http://***.onmicrosoft.com/***API
它有效,所以我得到了一个有效的 JWT,无需发送秘密。
为什么!?这不太安全吗? (我还注意到 OAuth 2.0 spec section 4.1.3 没有说明授权类型授权码需要秘密!?)
在没有秘密/基本身份验证的情况下使用 authorization_code 授权类型有什么影响 header?
without having to send a secret.
不正确。在 link you posted 中,请求还包括:
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
也许你没有注意到。这显示 client_secret
使用 HTTP 基本身份验证以编码形式传输。
由服务器决定客户端如何进行身份验证(如果需要)。来自规范:
If the client type is confidential or the client was issued client credentials (or assigned other authentication requirements), the client MUST authenticate with the authorization server as described in Section 3.2.1.
第 3.2.1 节指向第 2.3 节(严肃地说),其中说:
Clients in possession of a client password MAY use the HTTP Basic authentication scheme as defined in [RFC2617] to authenticate with the authorization server.
客户端密码也就是客户端密码。
所以正在传输秘密。
对所谓的机密客户端(具有客户端机密的客户端)使用授权码授予确实比使用 public 客户端更安全。
这是因为授权代码本身的交换作为 URL 参数在前端通道中发生,即通过浏览器,因此相对容易受到跨脚本、点击劫持等攻击,network/DNS 操纵等。这意味着专门的攻击者有可能在某些情况下(草率的用户、攻击者网络控制、草率的服务器实现中的重定向 URI 匹配等)窃取用户的授权码。
要用访问令牌交换授权代码,机密客户端必须在授权代码旁边的 HTTPS 保护调用中出示客户端机密,而 public 客户端没有任何方法确保它确实是指定的客户端。
这意味着攻击者模仿 public 客户端 相对 容易,因为这只需要非秘密信息(他可以获取 client_id
和来自他自己浏览器的 redirect_uri
)以及他可以通过上述攻击获取的授权 code
。
虽然获取机密客户端的授权代码的工作方式相同,但攻击者无法使用它并将其交换为访问令牌,因为为此他需要一个通常更难获得的客户端密码对于攻击者。秘密通常存储在后端存储的服务器上,并且仅通过安全的 HTTPs 通道进行通信,因此不会泄露。
将 grant_type=authorization_code
(或任何其他流程)与 public 客户端(没有秘密或以任何其他方式进行身份验证的客户端)一起使用的含义是授予的访问令牌确实不代表客户端直接访问资源的授权,它代表客户端代表用户访问资源的授权。
这就是为什么您会在 Azure AD 中注意到,当您注册本机客户端应用程序(public 客户端)时,您只能将其配置为对资源具有委派权限,而不是仅限应用程序权限。