Facebook OAuth 2.0的“代码”和“令牌”

Facebook OAuth 2.0 “code” and “token”

为什么在Facebook OAuth2身份验证流程中既需要"代码"又需要"令牌",如下所述:https://developers.facebook.com/docs/authentication/?

如果您查看OAuth对话框参考(https://developers.facebook.com/docs/reference/dialogs/oauth/),似乎您仅使用令牌来获取有关用户的信息,并且如果您指定了 response_type参数为tokencode,token,则您第一次获得令牌。

为什么您需要获取一个"代码",然后使用该代码获取一个"令牌",而不是直接获取令牌?

我猜我对OAuth的工作原理有一些误解,但是如果您第一次在对话框中获得令牌,似乎完全避免了对https://graph.facebook.com/oauth/access_token的请求。


让我们以一个简单的示例来区分身份验证代码与访问令牌。

您作为用户想尝试一个新的名为Highjack的Facebook应用程序。
因此,您单击该应用程序和Highjack应用程序。要求您登录您的Facebook帐户。完成后,Facebook将为您生成一个验证码。

然后,此代码将传递到Highjack服务器,该服务器使用其自己的FB客户端ID,FB机密和您的身份验证代码来获取访问令牌。

在上面的示例中,身份验证代码正在确认您作为用户是有效的FB用户。但是第二步说"作为FB用户,您正在授予对某些资源的Highjack应用访问权限"。

如果Highjack应用需要隐式授予(即直接访问令牌),则访问令牌也将对您可见,因为它已与浏览器交换。这意味着您现在可以使用访问令牌代表Highjack调用所有Facebook API。 (您只能使用访问令牌来获取您的个人信息,但Facebook无法知道谁在调用他们的API。)

由于我们有2个参与方(您和Highjack)通过Facebook进行身份验证,因此我们有2种折叠机制。


无耻地从Salesforce文档中借来的:

授权码

授权代码是由用户授权服务器创建并通过浏览器传递给客户端应用程序的代表用户访问授权的短暂令牌。客户端应用程序将授权代码发送到授权服务器,以获取访问令牌和(可选)刷新令牌。

访问令牌
客户端使用访问令牌代表最终用户发出经过身份验证的请求。它的寿命比授权码更长,通常为数分钟或数小时。当访问令牌过期时,尝试使用它将会失败,并且必须通过刷新令牌来获取新的访问令牌。


根据OAuth 2.0规范:

The authorization code provides a few important security benefits
such as the ability to authenticate the client, and the transmission
of the access token directly to the client without passing it through
the resource owner's user-agent, potentially exposing it to others,
including the resource owner.

因此,基本上-主要原因是限制获取访问令牌的参与者的数量。

"令牌"响应主要用于浏览器中的客户端(例如JavaScript客户端)。


如果查看授权码OAuth类型的流程,是的,有两个精算步骤:

1
2
1. <user_session_id, client_id> => authorization_code
2. <client_id, redirect_uri, authorization_code, client_secret> => access_token, refresh_token

在步骤1中:用户告诉OAuth服务器"我要验证此客户端(client_id)以访问我的资源。这是我的验证(user_session_id或其他方式)"

在步骤2中:客户端(client_id)告诉OAuth服务器"我已获得用户的授权(authorization_code),请给我一个访问令牌以供以后访问。这是我的身份验证(client_id和client_secret)"

您会看到,如果我们省略了步骤2,则无法保证客户端身份验证。任何客户端都可以使用不同的client_id调用step1,并获得该client_id而不是其自己的访问令牌。这就是为什么我们需要第二步。

如果您确实要结合步骤1和步骤2,则可以执行以下操作:

1
<client_id, redirect_uri, client_secret> => access_token, refresh_token

我们在Open Api平台中使用了这种方法,但尚未发现任何安全问题。

顺便说一句,实际上存在一个隐式授予类型,即:

1
<client_id, redirect_uri> => access_token, refresh_token

通常适用于没有服务器后端的仅客户端应用程序。在这种情况下,OAuth服务器必须确保重定向URI属于该客户端(例如,与寄存器redirect_uri相同)


之所以出现混淆,是因为用户代表自己而不是客户端应用通过授权服务器(即Facebook)进行身份验证。
保护客户端应用程序(使用https)和用户代理(浏览器)非常简单。

这是IETF-oauth(http://tools.ietf.org/html/draft-ietf-oauth-v2-threatmodel-08#section-3.4)的原始公式:

3.4。授权码

授权码代表一个中间结果
成功的最终用户授权过程,由客户端使用
获取访问权限并刷新令牌。授权码发送到
客户端的重定向URI(而不是令牌)有两个目的。

  • 基于浏览器的流将协议参数暴露给潜在用户
    攻击者通过URI查询参数(HTTP引荐来源网址),浏览器
    缓存或日志文件条目,并且可以重播。为了
    减少这种威胁,通过了短暂的授权代码
    代替令牌,并通过更安全的方式交换令牌
    客户端与授权服务器之间的直接连接。

  • 在直接验证过程中对客户端进行身份验证要简单得多
    客户端和授权服务器之间的请求比
    间接授权请求的上下文。后者会
    需要数字签名。


  • 答案)您需要/需要代码和令牌以提高安全性。

    根据Nate Barbettini的说法,我们想要交换访问令牌的身份验证代码的额外步骤,因为身份验证代码可以在前通道中使用(不太安全),而访问令牌可以在后通道中使用(更安全) 。

    因此,安全性的好处是访问令牌不会暴露给浏览器,因此无法从浏览器中拦截/获取。我们更加信任Web服务器,它通过反向渠道进行通信。然后,访问令牌是秘密的,可以保留在Web服务器上,而不会暴露给浏览器(即前端通道)。

    有关更多信息,请观看以下精彩视频:

    OAuth 2.0和OpenID Connect(以纯英语显示)


    从理论上讲,

    • 访问令牌无法告诉我们用户是否已通过身份验证,但身份验证代码已通过身份验证。
    • 身份验证代码不应用于获取对API的访问权限,而应使用访问令牌。

    如果您有一个没有后端或后端最少的单页应用程序或移动应用程序,则您的应用程序可能希望直接在前端访问用户的FB数据。因此,提供了访问令牌。

    在另一种情况下,您可能希望用户使用一些外部身份验证服务提供商(如Facebook,Google等)注册/登录到您的应用。在这种情况下,您的前端会将身份验证代码发送到后端,该代码可用于获取访问令牌从服务器端的Facebook。现在,您的服务器已启用,可以从服务器访问用户的FB数据。

    enter image description here


    基本上,作为Lix答案的扩展,访问代码路由允许资源所有者(即Facebook用户)撤消对其用户代理(即其浏览器)的授权,例如通过注销而无需撤消对脱机客户端(即您的应用程序)的授权。
    如果这并不重要,则无需使用访问代码路由。

    此外,提供访问代码以确保提供给服务器的令牌实际上已注册到资源所有者(即Facebook用户),而不是用户代理(或中间人)。

    这似乎类似于选择隐式授权代码授权流的问题。实际上,这似乎是相反的观点?!

    而且,正如德鲁所说,

    When the access token expires, attempts to use it will fail, and a new access token must be obtained via a refresh token.

    另一个是刷新令牌,但我认为在FB文档中解释得不够好。如果我是正确的,那么隐式授予(直接令牌)应该确实是短暂的,但这是必须执行的,而FB.js似乎隐藏了很多(我没有深入研究过的那个) 。

    如果我是正确的话,code%20token是一种优化,既允许用户代理拥有令牌,又允许服务器在单个请求中启动令牌交换过程(因为通过网络IO进行的任何操作都被认为是昂贵的,尤其是对于用户代理)。


    这是因为访问令牌是使用只有FB和客户端知道的共享密钥提供给经过授权的客户端(第三方应用)的。用户直接请求访问令牌的唯一方法是知道共享机密,这将使机密公开,并可能导致中间人攻击。此外,尽管FB可以保证与用户的安全连接,但FB不能保证将令牌移交给客户端的安全性。但是,FB(和OAuth2)确实需要客户端和FB之间的安全连接。访问令牌与客户端公共ID绑定在一起(通常是散列的),这意味着只有原始客户端应用程序才能使用它来请求令牌,因为秘密与授权代码一起发送以获得访问令牌。


    在带有Facebook的OAuth 2.0中,总体概念很简单,如下所示。

    步骤1.通过GET请求获取"授权码"

    1
    2
    3
    4
    5
    6
    7
    request URI: https://www.facebook.com/dialog/oauth
    Params:
        response_type=code
        client_id={add your"App id" got by registering app}
        redirect_uri={add redirect uri defined at the registration of app}
        scope={add the scope needed in your app}
    Headers: None

    步骤2.通过将授权代码作为POST请求发送来获取"访问令牌"

    1
    2
    3
    4
    5
    6
    7
    8
    9
        URI: https://graph.facebook.com/oauth/access_token
        Params:
            grant_type=authorization_code
            client_id=
            redirect_uri=
            code=<obtained authorization code from previous step>
        Headers:
            Authorization:Basic encode <App Id:App Secret> with base64
            Content-Type:application/json

    步骤3.使用从上一步获得的访问令牌并检索用户资源


    用户登录时会收到令牌。但是,当您执行其他操作时,可能需要更改令牌。 EG作为您的应用程序/页面进行发布,或作为具有offline_access的用户进行发布。