这个问题是关于尝试了解在 Android 等移动平台上实施 oauth 所涉及的安全风险。这里的假设是我们有一个 Android 应用程序,在代码中嵌入了消费者密钥/秘密。
假设消费者的秘密已经被泄露,并且黑客已经掌握了它,这会产生什么后果?
受损的消费者秘密假设 我是否正确地指出,受损的消费者秘密本身对用户的安全性或存储在用户与之交互的启用 OAuth 的提供者处的任何数据没有影响。数据本身不会受到损害,黑客无法检索。
黑客需要获得一个有效的用户访问令牌,而这要难得多。
黑客可以利用泄露的消费者机密做什么?我在陈述以下内容时是否也正确:
黑客可以设置/发布模仿我的应用程序的应用程序。
黑客可以吸引将通过 OAuth 流程的用户,通过黑客 OAuth 舞蹈(使用受损的消费者密钥/秘密)检索访问令牌。
用户可能会认为他正在处理我的应用程序,因为他会在授权过程中看到一个熟悉的名称(消费者密钥)。
当消费者通过黑客发出请求时,黑客可以轻松拦截访问令牌,并结合消费者秘密现在可以代表我签署请求以访问我的资源。
最终用户影响 假设
黑客使用我的消费者密码设置了应用程序/站点
我的一位用户被诱骗授权访问该应用程序/站点
可能会发生以下情况:
最终用户可能会注意到发生了一些可疑的事情,并通知服务提供商(例如:谷歌)有关恶意应用程序
然后服务提供者可以撤销消费者密钥/秘密
OAuth 消费者(我的应用程序)影响:我的应用程序(包含消费者密码)需要更新,否则我的所有客户将无法授权我的应用程序代表他们执行请求(因为我的消费者密码将不再有效)。
委托所有 OAuth 流量 尽管可以通过中间网络服务器委托大量 OAuth 交互(进行 OAuth 舞蹈并将访问令牌发送给用户),但还必须代理所有服务交互,作为消费者密钥签署每个请求都需要 /secret。这是将消费者密钥/秘密保存在移动应用程序之外并存储在中间网络服务器上更安全的地方的唯一方法吗?
替代方案 这个代理有替代方案吗?是否可以将消费者秘密存储在中间网络服务器上,并具有某种机制,Android 应用程序(在市场上发布并正确签名)可以向中间网络服务器发出安全请求以获取消费者秘密并存储它在应用程序内部?是否可以实现一种机制,使中间网络服务器“知道”这是一个请求获取消费者秘密的官方 android 应用程序,并且中间网络服务器只会将消费者秘密分发给该特定的 android 应用程序?
摘要:我会冒险并在客户端应用程序中保守秘密。
代理服务器替代:
您可以合理缓解我在下面列出的问题并使代理工作的唯一方法是走完整的九码 - 将用于处理第三方 Web 服务上的资源的所有业务逻辑移动到您的代理服务器,并且使客户端应用程序成为具有丰富 UI 的哑终端。这样,恶意应用程序能够让代理代表它执行的唯一操作将只是您的业务逻辑合法需要的操作。
但是现在你遇到了一大堆其他问题,必须处理可靠性和可扩展性。
关于为什么简单代理不起作用的长时间考虑:
有些人在遇到问题时会想“我知道,我会添加自己的代理服务器” 现在他们有两个问题。 (向 Jamie Zawinski 道歉)
你的假设在很大程度上是正确的。直到您开始考虑自己的服务器,它是否会保密并代理客户端应用程序的调用,或者它会尝试确定应用程序是否合法并提供秘密。在这两种方法中,您仍然要解决“这个请求来自我编写的一段代码”的问题吗?
让我重复一遍 - 没有办法区分特定软件正在运行的线路。如果消息中的数据看起来正确,则无法证明是另一个应用程序发送了该消息。
归根结底,如果我正在编写一个恶意应用程序,我不在乎我是否真的知道真正的秘密,只要我能让知道它的人代表我工作即可。那么,如果您认为恶意应用程序可以将您的应用程序模拟到第三方 OAuth 服务器,您为什么确定它不能将您的应用程序模拟到您的代理?
但是等等,还有更多。您的代理服务所在的域是您对客户和 OAuth 提供者的身份(如 OAuth 提供者向最终用户显示的那样)。如果恶意应用程序可以使您的服务器做坏事,那么不仅您的密钥被撤销,而且您的公共网络身份也不再受信任。
我将从显而易见的开始 - 无法区分特定软件正在运行的线路。如果消息中的数据看起来正确,则无法证明是另一个应用程序发送了该消息。
因此,任何依赖于应用程序端存储秘密的算法都可能被欺骗。 OAuth 的优势在于它从不将用户的凭据提供给应用程序,而是为应用程序提供它自己的临时凭据,用户可以在必要时撤销这些凭据。
当然,这里的弱点是,一个足够好的应用程序可以让用户信任它,而不是在它完成其邪恶行为之前撤销凭据。
但是,缓解这种情况的一种方法是 Google 使用 3-legged OAuth 的方法,而不是标准的 2-legged。在 3-legged OAuth 中,没有预先分配的秘密,但在每次身份验证时,都会发布一个新的访问令牌秘密以及每个访问令牌。虽然最终这会遇到同样的缺点,因为一个坏的应用程序可以从它的进程中读取好的应用程序的令牌秘密,它确实导致用户每次需要新的访问令牌时都必须批准应用程序访问。
当然,这也意味着它对用户来说有点不方便和烦人。
"com.your.app_name"
而不是context.getPackageInfo()
?