使用 OAuth 协议时,您需要从要委托的服务中获取一个秘密字符串。如果您在 Web 应用程序中执行此操作,您可以简单地将秘密存储在您的数据库或文件系统中,但是在移动应用程序(或桌面应用程序)中处理它的最佳方法是什么?
将字符串存储在应用程序中显然不好,因为有人很容易找到并滥用它。
另一种方法是将其存储在您的服务器上,并让应用程序在每次运行时获取它,而不是将其存储在手机上。这几乎同样糟糕,因为您必须在应用程序中包含 URL。
我能想到的唯一可行的解决方案是首先正常获取访问令牌(最好使用应用程序内的 Web 视图),然后通过我们的服务器路由所有进一步的通信,这会将秘密附加到请求数据并进行通信与提供者。再说一次,我是一个安全菜鸟,所以我真的很想听听一些知识渊博的人对此的看法。在我看来,大多数应用程序都不会用这些长度来保证安全性(例如,Facebook Connect 似乎假设您将秘密放入应用程序中的字符串中)。
另一件事:我不相信最初请求访问令牌涉及秘密,因此可以在不涉及我们自己的服务器的情况下完成。我对么?
是的,这是我们自己面临的 OAuth 设计的一个问题。我们选择通过我们自己的服务器代理所有呼叫。 OAuth 在桌面应用程序方面并未完全淘汰。在不更改 OAuth 的情况下,我发现的问题没有完美的解决方案。
如果您考虑一下并问我们为什么有秘密的问题,主要是为了提供和禁用应用程序。如果我们的秘密被泄露,那么提供商只能真正撤销整个应用程序。由于我们必须在桌面应用程序中嵌入我们的秘密,我们有点搞砸了。
解决方案是为每个桌面应用程序设置不同的秘密。 OAuth 不会让这个概念变得简单。一种方法是让用户自己创建一个秘密,然后自己将密钥输入到您的桌面应用程序中(一些 Facebook 应用程序在很长一段时间内都做了类似的事情,让用户去创建 Facebook 来设置他们的自定义测验和废话)。这对用户来说不是很好的体验。
我正在为 OAuth 的委托系统提出建议。这个概念是,使用我们从提供商那里获得的我们自己的密钥,我们可以向我们自己的桌面客户端(基本上每个桌面应用程序一个)发布我们自己的委托密钥,然后在身份验证过程中我们将该密钥发送到顶层回拨给我们并与我们重新验证的提供商。这样我们就可以撤销我们发布给每个桌面客户端的自己的秘密。 (从 SSL 中借鉴了很多它的工作原理)。整个系统对于增值网络服务以及将调用传递给第三方网络服务都是完美的。
如果顶级提供者提供 API 来生成和撤销新的委托秘密,则该过程也可以在没有委托验证回调的情况下完成。 Facebook 通过允许 Facebook 应用程序允许用户创建子应用程序来做类似的事情。
网上有一些关于这个问题的讨论:
http://blog.atebits.com/2009/02/fixing-oauth/ http://groups.google.com/group/twitter-development-talk/browse_thread/thread/629b03475a3d78a1/de1071bf4b820c14#de1071bf4b820c14
Twitter 和 Yammer 的解决方案是身份验证 pin 解决方案:https://dev.twitter.com/oauth/pin-based https://www.yammer.com/api_oauth_security_addendum.html
使用 OAUth 2.0,您可以将秘密存储在服务器上。使用服务器获取访问令牌,然后将其移至应用程序,您可以从应用程序直接调用资源。
对于 OAuth 1.0 (Twitter),进行 API 调用需要密钥。通过服务器代理调用是确保机密不被泄露的唯一方法。
两者都需要一些机制,您的服务器组件知道它是您的客户端调用它。这往往是在安装时完成的,并使用特定于平台的机制在对服务器的调用中获取某种应用程序 ID。
(我是 OAuth 2.0 规范的编辑)
一种解决方案可能是将 OAuth 密码硬编码到代码中,而不是作为纯字符串。以某种方式混淆它 - 将其分割成段,将字符移动一个偏移量,旋转它 - 做任何或所有这些事情。破解者可以分析您的字节码并找到字符串,但混淆代码可能很难弄清楚。
这不是一个万无一失的解决方案,而是一个便宜的解决方案。
根据漏洞利用的价值,一些天才破解者可以不遗余力地找到您的密码。您需要权衡这些因素——前面提到的服务器端解决方案的成本、破解者花更多精力寻找您的密码的动机,以及您可以实施的混淆的复杂性。
不要将秘密存储在应用程序中。
您需要有一个应用程序可以通过 https 访问的服务器(显然),并且您将秘密存储在其上。
当有人想通过您的移动/桌面应用程序登录时,您的应用程序将简单地将请求转发到服务器,然后服务器将附加密码并将其发送给服务提供商。然后,您的服务器可以告诉您的应用程序是否成功。
然后,如果您需要从服务(facebook、google、twitter 等)获取任何敏感信息,应用程序会询问您的服务器,并且只有在正确连接的情况下,您的服务器才会将其提供给应用程序。
除了将其存储在服务器上之外,实际上没有任何选择。客户端没有什么是安全的。
笔记
也就是说,这只会保护您免受恶意客户端的侵害,但不会保护您免受恶意客户端的侵害,也不会保护客户免受其他恶意客户端的侵害(网络钓鱼)...
OAuth 在浏览器中是比在桌面/移动设备上更好的协议。
授权代码授予类型有一个新的扩展,称为代码交换证明密钥 (PKCE)。有了它,您就不需要客户端密码了。
PKCE (RFC 7636) 是一种保护不使用客户端密码的公共客户端的技术。它主要由本地和移动应用程序使用,但该技术也可以应用于任何公共客户端。它需要授权服务器的额外支持,因此仅在某些提供程序上受支持。
有关详细信息,您可以阅读完整的 RFC 7636 或 this short introduction。
这是需要考虑的事情。 Google 提供了两种 OAuth 方法……用于 Web 应用程序,您在其中注册域并生成唯一密钥,以及为您使用“匿名”密钥的已安装应用程序。
也许我在阅读中掩盖了某些内容,但似乎与已安装的应用程序共享您的 webapp 的唯一密钥可能比在官方安装的应用程序方法中使用“匿名”更安全。
使用 OAuth 2.0,您可以简单地使用客户端流程来获取访问令牌,然后使用此访问令牌来验证所有进一步的请求。那么你根本不需要秘密。
可以在此处找到有关如何实现此功能的详细说明:https://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified#mobile-apps
我没有丰富的 OAuth 经验 - 但不是每个请求不仅需要用户的访问令牌,还需要应用程序使用者密钥和秘密?因此,即使有人窃取了移动设备并试图从中提取数据,他们也需要应用程序密钥和秘密才能真正做任何事情。
我一直认为 OAuth 背后的目的是让每个拥有 mashup 的 Tom、Dick 和 Harry 都不必明文存储您的 Twitter 凭据。我认为它很好地解决了这个问题,尽管它有局限性。此外,它的设计并没有真正考虑到 iPhone。
我同意费利西兹的观点。 OAuth 虽然比 Basic Auth 更好,但要成为移动应用程序的良好解决方案还有很长的路要走。我一直在尝试使用 OAuth 向 Google App Engine 应用程序验证手机应用程序。您无法在移动设备上可靠地管理消费者机密这一事实意味着默认使用“匿名”访问。
Google App Engine OAuth 实施的浏览器授权步骤会将您带到一个页面,其中包含如下文本:“站点
YourApp(yourapp.appspot.com) - 不隶属于 Google
ETC
它从您提供的回调 url 中使用的域/主机名中获取
Google OAuth 授权页面也确实包含许多警告,根据您使用的是“匿名”、消费者机密还是公钥,这些警告具有 3 级严重性。
对于不精通技术的普通用户来说,这是相当可怕的事情。我不希望这种方式的注册完成率很高。
这篇博文阐明了消费者秘密如何不能真正与已安装的应用程序一起使用。 http://hueniverse.com/2009/02/should-twitter-discontinue-their-basic-auth-api/
严格来说,Facebook 尚未实施 OAuth(目前),但他们已经实施了一种方法,让您不要在 iPhone 应用程序中嵌入您的秘密:https://web.archive.org/web/20091223092924/http://wiki.developers.facebook.com/index.php/Session_Proxy
至于 OAuth,是的,我想得越多,我们就有点吃不消了。也许 this 会解决它。
这些解决方案都不能阻止确定的黑客嗅探从他们的移动设备(或模拟器)发送的数据包,以查看 http 标头中的客户端机密。
一种解决方案可能是拥有一个动态机密,该机密由使用私有 2 路加密密钥和算法加密的时间戳组成。然后,该服务解密该密钥并确定时间戳是否为 +/- 5 分钟。
这样,即使机密被泄露,黑客也最多只能使用 5 分钟。
我还在尝试提出一种用于移动 OAuth 身份验证的解决方案,并且通常将机密存储在应用程序包中。
我突然想到了一个疯狂的想法:最简单的想法是将秘密存储在二进制文件中,但以某种方式进行了混淆,或者换句话说,您存储了一个加密的秘密。所以,这意味着你必须存储一个密钥来解密你的秘密,这似乎让我们绕了一圈。但是,为什么不直接使用操作系统中已经存在的密钥,即它是由操作系统定义的,而不是由您的应用程序定义的。
所以,为了澄清我的想法,你选择一个由操作系统定义的字符串,不管是哪一个。然后使用此字符串作为密钥加密您的秘密,并将其存储在您的应用程序中。然后在运行时,使用密钥解密变量,这只是一个操作系统常量。任何偷看你的二进制文件的黑客都会看到一个加密的字符串,但没有密钥。
那会奏效吗?
正如其他人所提到的,在设备上本地存储秘密应该没有真正的问题。
最重要的是,您始终可以依赖基于 UNIX 的 Android 安全模型:只有您的应用程序才能访问您写入文件系统的内容。只需将信息写入您应用的默认 SharedPreferences 对象即可。
为了获得秘密,必须获得对 Android 手机的 root 访问权限。