OAuth 协议入门
在过去的几十年里,网页已经从静态的、主要用于信息展示的工具转变为功能齐全的应用程序。 与此同时,Web 开发者为他们的 Web 应用程序创建了接口,以便其他开发者可以开发与该 Web 应用程序协同工作的应用程序。 例如,想想您手机上任何 Web 服务的应用程序。 这之所以成为可能,完全是因为 Web 服务开发者构建了应用程序编程接口 (API)。
API 允许开发者在不失去对其服务或其行为方式的控制的情况下,让其他人访问其服务的某些功能。 随着这些 API 的发展,用户身份验证和安全问题也随之出现。 每次您想对服务执行某些操作时,都必须发送您的用户凭据(通常是用户 ID 和密码)。 这会将用户暴露给感兴趣的各方,并使身份验证变得不可靠。 用户使用的应用程序也可能存储密码,并允许其他应用程序或人员访问用户的帐户。
OAuth 应运而生。
OAuth 旨在成为一种简单、安全的方式来验证用户身份,而无需将他们的秘密凭据暴露给任何不应该访问它们的人。 它由 Blaine Cook 于 2006 年 11 月启动,当时他正在为 Twitter 开发 OpenID 实现。 在开发过程中,Blaine 意识到 Twitter API 无法处理已使用 OpenID 验证身份的用户。 他与 Chris Messina 取得联系,以寻找一种将 OpenID 与 Twitter API 一起使用的方法。 在稍后与其他人进行多次对话后,OAuth 诞生了。 同年 12 月,OAuth Core 1.0 最终定稿。
自 2010 年 8 月 31 日起,所有第三方 Twitter 应用程序都必须使用 OAuth。
您可以将 OAuth 想象成 ATM 卡。 您的银行账户(Web 服务)关联着大量的服务,只要您将卡插入 ATM 并输入 PIN 码,就可以使用所有这些服务。 最终,任何拥有您的卡和 PIN 码的人都可以完全访问您的帐户,并可以使用所有这些便捷的服务对您的帐户执行他们想做的任何事情。 但是,您也可以将您的卡用作信用卡,在这种情况下,用签名代替您对 PIN 码的了解。 在这种情况下,持卡人只能进行非常有限的交易,即对帐户余额进行扣款。
如果有人试图在没有您的卡的情况下使用您的签名向您的帐户收费,那将不起作用。 如果您有卡但没有签名,也会发生相同的结果(理论上)。 OAuth 的工作方式类似。 如果应用程序拥有您的签名,它可以代表您向 Web 服务发出 API 调用,但该签名仅适用于该应用程序。 允许一方代表他人访问其资源是 OAuth 协议的核心。
假设用户 Jane 是照片分享网站 photosharingexample.com(服务提供商)的会员,她在该网站上保存了她所有的照片。 圣诞节时,她决定给母亲送一些她家人的精美照片,因此她在另一个名为 photoprintingexample.com(消费者)的网站上注册了一个帐户。 新网站 photoprintingexample.com 具有一项功能,允许 Jane 选择存储在她 photosharingexample.com 帐户中的照片,并将它们传输到她的 photoprintingexample.com 帐户进行打印。
Photoprintingexample.com 已经从 photosharingexample.com 注册了消费者密钥和消费者密钥。
Consumer Key: dpf43f3p2l4k3l03 Consumer Secret: kd94hf93k423kf44
Jane 选择使用此服务。 当 photoprintingexample.com 尝试从 photosharingexample.com 检索 Jane 的照片时,它收到 HTTP 401 Unauthorized 错误,表明这些照片是私有的。 这是预期的,因为 Jane 尚未授权 photoprintingexample.com 访问她的 photosharingexample.com 帐户。 消费者向服务提供商发送以下请求
https://photosharingexample.com/request_token? ↪oauth_consumer_key=dpf43f3p2l4k3l03&oauth_ ↪signature_method=PLAINTEXT&oauth_signature= ↪kd94hf93k423kf44%26&oauth_timestamp= ↪1191242090&oauth_nonce=hsu94j3884jdopsl&oauth_version=1.0
对于服务提供商来说,使用 nonce 可能会非常昂贵,因为它们需要持久存储所有曾经收到的 nonce 值。 为了降低服务器实现的成本,OAuth 在每个请求中添加了一个时间戳值,这允许服务提供商仅在有限的时间内保留 nonce 值。 当收到时间戳早于保留时间范围的请求时,该请求将被拒绝,因为服务提供商不再拥有该时间段的 nonce。
Nonce
术语 nonce 的意思是“一次性使用的数字”,它是一个唯一且通常是随机的字符串,旨在唯一标识每个签名请求。
服务提供商检查请求的签名,并回复未经授权的请求令牌
oauth_token=hh5s93j4hdidpola&oauth_token_secret=hdhd0244k9j7ao03
消费者将 Jane 的浏览器重定向到服务提供商用户授权 URL
http://photosharingexample.com/authorize?oauth_token= ↪hh5s93j4hdidpola&oauth_callback= ↪http%3A%2F%2Fphotoprintingexample.com%2Frequest_token_ready
如果 Jane 已登录 photosharingexample.com,此页面将询问她是否授权 photoprintingexample.com 访问她的帐户。 如果 Jane 授权请求,她的浏览器将被重定向回 http://photoprintingexample.com/request_token_ready?oauth_token=hh5s93j4hdidpola,告知消费者请求令牌已获得授权。 然后,消费者将使用以下地址将请求令牌交换为访问令牌
https://photosharingexample.com/access_token? ↪oauth_consumer_key=dpf43f3p2l4k3l03&oauth_token= ↪hh5s93j4hdidpola&oauth_signature_method=PLAINTEXT& ↪oauth_signature=kd94hf93k423kf44%26hdhd0244k9j7ao03& ↪oauth_timestamp=1191242092&oauth_nonce= ↪dji430splmx33448&oauth_version=1.0
这将返回响应中的访问令牌
oauth_token=nnch734d00sl2jdk&oauth_token_secret=pfkkdhi9sl3r4s00
此交换仅在 Jane 首次尝试从 photoprintingexample.com 访问她的 photosharingexample.com 照片时发生。 之后,每次都只会发生以下情况。
现在,消费者已做好充分准备来访问 Jane 的照片。 首先,消费者需要生成请求签名。 第一步是创建签名基字符串。 这是以下元素的组合
oauth_consumer_key: dpf43f3p2l4k3l03 oauth_token: nnch734d00sl2jdk oauth_signature_method: HMAC-SHA1 oauth_timestamp: 1191242096 oauth_nonce: kllo9940pd9333jh oauth_version: 1.0 file: family.jpg size: original
最终,您得到字符串
GET&http%3A%2F%2Fphotosharingexample.com%2Fphotos& ↪file%3Dfamily.jpg%26oauth_consumer_key% ↪3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh% ↪26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp% ↪3D1191242096%26oauth_token%3Dnnch734d00sl2jdk% ↪26oauth_version%3D1.0%26size%3Doriginal"
如果您的请求是通过 SSL 传输的,则请求可以是纯文本。 但是,绝大多数网站不使用 SSL,因此签名字符串必须进行编码。
传统上,HTTP 协议使用一种称为“基本”的身份验证方法,用户提供用户名和密码以获得对受保护资源的访问权限。 该过程的主要缺陷是这些凭据以纯文本形式传递,任何监听的人都可以清晰地读取和存储它们。 为了保护用户的凭据,OAuth 使用数字签名而不是在每个请求中发送凭据。
此数字签名用于验证发出的请求是否合法且未被篡改。 哈希算法用于实现此目的。 为了使接收者能够验证请求是否来自声称的发送者,哈希算法与共享密钥相结合。 如果双方就只有双方知道的密钥达成一致,他们可以将其添加到正在哈希的内容中。 这可以通过简单地将密钥附加到内容,或通过使用具有内置密钥机制的更复杂的算法(例如 HMAC)来完成。
哈希算法
将数据(任意大小)压缩成小得多的值(摘要)的过程,以完全可重现(单向)的方式进行。 对相同数据使用相同的哈希算法始终会产生相同的小值。
对于此示例,假设服务提供商允许 HMAC-SHA1 签名。 因此,编码后的签名字符串变为
tR3+Ty81lMeYAr/Fid0kMTYa/WM=
总而言之,消费者对照片的请求是
http://photosharingexample.com/photos?file=vacation.jpg&size= ↪original&oauth_consumer_key=dpf43f3p2l4k3l03& ↪oauth_token=nnch734d00sl2jdk&oauth_signature_method= ↪HMAC-SHA1&oauth_signature=tR3%2BTy81lMeYAr%2FFid0kMTYa% ↪2FWM%3D&oauth_timestamp=1191242096&oauth_nonce= ↪kllo9940pd9333jh&oauth_version=1.0
服务提供商执行与消费者执行的相同工作流程来计算请求的签名。 然后,它将其计算的签名与提供的签名进行比较。 如果两者匹配,则接收者可以确信请求在传输过程中未被修改。 然后,服务提供商响应请求的照片。
从编程的角度来看,此过程可能令人生畏。 有许多为 OAuth 服务器和客户端编写的库,适用于多种编程语言。
用于验证请求签名的共享密钥称为消费者密钥。 因为它对于此事务的完整性至关重要,所以必须保守此数据。 在基于 Web 的消费者(例如 Web 服务)的情况下,很容易确保消费者密钥的安全。 如果消费者是客户端应用程序,则必须在应用程序的每个副本中硬编码消费者密钥。 这意味着消费者密钥可能会被发现,这会损害任何桌面应用程序的完整性。
在 OAuth 1.0 协议中发现了一个已知的会话固定攻击漏洞,该漏洞允许攻击者访问目标用户的帐户。 攻击者登录到消费者网站并启动 OAuth 授权过程。 攻击者保存授权请求页面,而不是单击提交。 这会存储请求令牌和密钥。 攻击者向受害者发送链接,如果单击该链接,将继续攻击者启动的授权过程。 完成后,攻击者将可以通过使用的消费者访问受害者的受保护资源。
Adrian Hannah 是一位终身系统管理员,他试图找到一个安顿下来的好地方。 他目前在印第安纳州的联邦政府工作。