为啥我要传输 `client_secret` 来获取 `access_token`?

Posted

技术标签:

【中文标题】为啥我要传输 `client_secret` 来获取 `access_token`?【英文标题】:Why should I transmit `client_secret` to obtain an `access_token`?为什么我要传输 `client_secret` 来获取 `access_token`? 【发布时间】:2011-11-15 09:26:10 【问题描述】:

为了从 Facebook 获取 access_token,您必须传输您的app_id、您在授权请求后收到的code,以及您的应用程序的secret_key

为什么我要永远传输我的密钥?这似乎很不安全。这是 OAuth 2.0 规范的要求吗?

作为一个相关问题,当我的请求已经用我的consumer_key 签名时,为什么我需要传输app_id

我有一个可以工作的应用程序,我只是不明白这些要求。

【问题讨论】:

OAuth 2.0 spec 中没有要求在请求访问令牌时发送密钥。 【参考方案1】:

这是OAuth 2.0 spec, section 4.1.3 的要求。

如果客户端类型是机密的或已获得客户端凭据 (或分配的其他身份验证要求),客户端必须 使用授权服务器进行身份验证,如中所述 第 3.2.1 节

而section 3.2.1 指的是section 2.3。具体来说,section 2.3.1 说:

或者,授权服务器可以允许包括 使用以下内容在请求正文中的客户端凭据 参数:

client_id

   REQUIRED.  The client identifier issued to the client during
   the registration process described by Section 2.2.

client_secret

   REQUIRED.  The client secret.  The client MAY omit the
   parameter if the client secret is an empty string.

OAuth 2.0 确实提供了其他方式,但通过选择这种方式,Facebook 完全符合规范。现在为什么Facebook 选择了这种方法,可能只有 Facebook 可以回答。

【讨论】:

client_secret 是否应该与 consumer_secret 不同?我不明白 client_idclient_secret 提供的内容超出了 consumer_keyconsumer_secret 提供的内容。 客户是消费者。因此,client_secret 就是 Facebook 所说的 App Secret。 client_id 是 Facebook 所称的 App ID/API 密钥。在此过程中,您的请求未使用您的密钥签名。这些参数用于在您请求令牌时对您的应用进行身份验证。 密钥永远被发送是非常奇怪的。曾经。这就是为什么它是一个秘密密钥。应该有一个标识符、PUBLIC 密钥(可选)和密钥。密钥用于对标识符和公钥进行签名。但 OAuth 将 SSL 视为万能的安全性。所以它并不在意,因为当您与授权服务器通信时,它总是通过 TLS 进行的。 (通常,密钥用于 MLS。【参考方案2】:

除了作为 Oauth2 的要求外,还需要在此步骤中使用 client_secret 来验证您确实是您声称的人。

这一切都归结为为什么这个过程是这样的......

从安全角度来看,您从第一个请求返回的“代码”本身就很弱。它可能会在重定向链接中劫持返回给您,我经常看到该链接在没有 SSL 保护的情况下进入登录页面。即使您的网站使用 100% HTTPS,一切都不是完全安全的。有人可以通过查看记录在 Web 服务器访问日志中的请求 URL 找到代码。

即使您在白金汉宫这一侧拥有最严密的安全环境来控制对您服务器的访问,如果您参加科技圈已有数年以上,您就会知道有人会在某个时候“归档”您的在不太安全的地方记录日志。可能在他们留在星巴克的 U 盘上……

如果您使用的是服务器端 API 流,没有什么可以避免这种情况。与在客户端浏览器中运行的 javascript 不同,您不能在哈希之后添加临时代码以防止其被记录,因为浏览器客户端不会在请求中发送任何超过哈希标记的内容。 JS可以拦截重定向Url,并解析出Hash标签后面的东西,这就是为什么JS Oauth2流程只返回access_token而无需额外的中间代码歌舞。 JS 端也不需要 Client_Secret,这很好,因为当您在 javascript 中输入密码和密钥时,通常会不赞成。

现在,为了防止这个中间代码被坏人用来获取访问令牌,Client_ID 和 Client_Secret 会一起发送,以便 API 服务器可以验证您是您声称的身份并且您拥有授权将代码兑换为 access_token。没有什么比共享秘密更重要的了!

由于代码在到期前的使用期限非常短(基本上是为了让您立即将其兑换为 access_token),因此不太可能出现有人窃取代码并试图暴力破解 Client_Secret 的危险。

使用短窗口和 client_secret(当然通过 ssl)的组合提供了一个您稍后与您的客户端凭据交换的信息

【讨论】:

【参考方案3】:

注意这些词......不推荐。

2.3.1。客户密码

拥有客户端密码的客户端可以使用 HTTP Basic [RFC2617] 中定义的身份验证方案,用于进行身份验证 授权服务器。客户端标识符使用 “application/x-www-form-urlencoded”编码算法 附录B,编码值作为用户名;客户端 密码使用相同的算法进行编码并用作 密码。授权服务器必须支持 HTTP Basic 用于认证客户端的认证方案 客户密码。

例如(带有额外的换行符仅用于显示目的):

 Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3

或者,授权服务器可以支持包括 使用以下内容在请求正文中的客户端凭据 参数:

client_id 必需的。期间发给客户端的客户端标识符 第 2.2 节描述的注册过程。

client_secret 必需的。客户机密。客户端可以省略 如果客户端密码为空字符串,则为参数。

使用这两个在请求正文中包含客户端凭据 不推荐使用参数,应仅限于无法使用的客户端 直接使用 HTTP Basic 身份验证方案(或其他 基于密码的 HTTP 身份验证方案)。 参数只能 在请求正文中传输,并且不得包含在 请求 URI。

例如,刷新访问令牌的请求(第 6 节)使用 正文参数(带有用于显示目的的额外换行符 仅):

 POST /token HTTP/1.1
 Host: server.example.com
 Content-Type: application/x-www-form-urlencoded

 grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
 &client_id=s6BhdRkqt3&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw

授权服务器必须要求使用 TLS,如 使用密码验证发送请求时的第 1.6 节。

由于此客户端身份验证方法涉及密码,因此 授权服务器必须保护任何使用它的端点 暴力攻击。

【讨论】:

以上是关于为啥我要传输 `client_secret` 来获取 `access_token`?的主要内容,如果未能解决你的问题,请参考以下文章

http与https的区别,为啥https比http安全

为啥在进行本地搜索时会收到 MKErrorDomain 错误?

Java 中,对Oracle Clob中的图片Base64进行解码后用System.out.println() 输出为啥成乱码,求高手帮忙。

为啥我要重载方法?

无法读取未定义的属性“client_secret”

为啥我要启动一个“暂停”的线程?