为移动应用程序创建API-身份验证和授权


189

总览

我正在为我的应用程序创建一个(REST)API。最初/主要目的是供移动应用程序(iPhone,Android,Symbian等)使用。我一直在研究基于Web的API的身份验证和授权的不同机制(通过研究其他实现)。我已经把大部分基本概念都束之高阁,但仍在一些方面寻求指导。我想做的最后一件事是重新发明轮子,但是我没有找到任何适合我标准的标准解决方案(但是我的标准可能会被误导,因此也随时可以批评我)。另外,我希望所有使用它的平台/应用程序的API都相同。

oAuth

我会继续反对oAuth,因为我知道这可能是第一个提供的解决方案。对于移动应用程序(或更确切地说是非Web应用程序),离开应用程序(转到Web浏览器)进行身份验证似乎是错误的。另外,浏览器无法(我知道)将回调返回给应用程序(尤其是跨平台)。我知道有几个应用程序可以做到这一点,但是感觉不对,并中断了应用程序UX。

要求

  1. 用户在应用程序中输入用户名/密码。
  2. 每个API调用均由调用应用程序标识。
  3. 开销降至最低,并且对于开发人员而言,auth方面很直观。
  4. 该机制对于最终用户(不公开其登录凭据)和开发人员(不公开其应用程序凭据)都是安全的。
  5. 如果可能,则不需要https(绝不是硬要求)。

我当前的实施思想

外部开发人员将请求一个API帐户。他们将获得一个apikey和apisecret。每个请求至少需要三个参数。

  • apikey-在注册时提供给开发人员
  • 时间戳-兼用作给定apikey的每个消息的唯一标识符
  • hash-时间戳+ apisecret的哈希

需要apikey来标识发出请求的应用程序。时间戳记的行为与oauth_nonce类似,并且避免/减轻了重播攻击。哈希确保请求实际上是从给定apikey的所有者发出的。

对于经过身份验证的请求(代表用户的请求),我仍然不确定要使用access_token路由还是使用用户名和密码哈希组合。无论哪种方式,在某个时候都将需要用户名/密码组合。因此,当这样做时,将使用多个信息(apikey,apisecret,时间戳)和密码的哈希。 我希望在这方面提供反馈。 仅供参考,他们必须先对密码进行哈希处理,因为我不会在不进行哈希处理的情况下将密码存储在系统中。

结论

仅供参考,这并不是要求通常如何构建/结构化API,而仅仅是要求如何仅从应用程序内部处理身份验证和授权。

随机想法/奖金问题

对于仅要求将apikey作为请求的一部分的API,如何防止apikey所有者以外的其他人看到apikey(因为是明文发送的),并提出过多的请求以使它们超过使用限制?也许我只是在考虑这个问题,但是不应该有什么东西可以验证对apikey所有者进行了验证的请求吗?在我的情况下,这是apisecret的目的,它不会被散列而不会显示/传输。

说到哈希,md5 vs hmac-sha1呢?当所有值都用足够长的数据(即apisecret)进行哈希处理时,真的重要吗?

我以前一直在考虑向用户密码哈希添加每用户/行盐。如果要这样做,应用程序如何能够在不知道使用盐的情况下创建匹配的哈希?


1
希望能得到更多的评论/建议。这个问题是否太含糊/模棱两可?
jsuggs 2010年

6
这个问题是完美的,但是即使在将近2年之后,oauth的实现也似乎是不可思议的。我还有一个额外的维度:我不想使用loginName / password对-我想在android / ios上使用Google身份验证(Symbian被WWF宣布为“几乎绝种”),我拒绝为此开发Windows Mobile(无论如今如何称呼)。
Tony gil 2012年

8
荒谬的是,正如每个人所建议的那样,oauth 2.0 ive尚未找到一个清晰,简单的教程或示例,使用通用英语来解释步骤,要求,应该做的和不应该做的....
ChuckKelly 2013年

2
阅读此特定的OAuth2.0流程(资源所有者密码流程)。没有重定向到网站。 techblog.hybris.com/2012/06/11/...
富兰克林

1
我也在寻找相同的答案。我发现最近写了一篇好文章。我希望这有帮助。 stormpath.com/blog/the-ultimate-guide-to-mobile-api-security
Rails的

Answers:


44

我在我的项目中考虑进行登录的方式是:

  1. 登录之前,用户请求 login_token从服务器。这些是应要求生成并存储在服务器上的,并且使用寿命可能很有限。

  2. 登录应用程序将计算用户密码的哈希值,然后使用哈希密码login_token以获取值,然后他们返回login_token和组合的哈希值。

  3. 服务器检查login_token是已生成的,并将其从有效login_tokens 列表中删除。然后,服务器将其存储的用户密码哈希与结合起来,login_token并确保它与提交的组合令牌匹配。如果匹配,则说明您已对用户进行身份验证。

这样做的好处是,您永远不会在服务器上存储用户密码,永远不会以明文形式传递密码,密码散列只会在创建帐户时以明文形式传递(尽管可能有解决方法),并且应该可以避免重放攻击,因为 login_token数据库中删除时。


谢谢,我忘了在应用程序端添加有关哈希密码的部分。我不会以明文形式存储用户密码(存储前我会进行哈希处理)。
jsuggs 2010年

2
我看到了这种方法的缺点:您不能在数据库中存储加盐的密码。如果攻击者将手放在您的数据库上,则无需进行任何解密。由于密码散列是此方案中的真实密码。
sigod

2
@sigod你是正确的。尽管我认为这里存在一个基本的二分法-您要么需要信任您的传输,要么您需要信任您的存储。使用加盐密码的登录系统信任传输层-从而将密码从用户直接传递给身份验证系统。这种情况不信任传输层(我认为这是因为我所针对的平台对SHTTP的支持不佳)。如果您信任传输层,则可以进行其他折衷。
Michael Anderson

我有3个问题:1)用户密码永远不会存储在服务器上吗?在步骤2中,您提到它存储了散列用户的密码。2)用户密码永远不会以明文形式传递。但是它实际上是在客户端上进行哈希处理,然后与服务器上的哈希密码进行比较,这与以明文方式传递和存储该密码几乎相同,这样做的目的是什么?3)此方法假定攻击者不知道如何对login_token +密码进行哈希处理,这违反了Kerckhoffs原理,并使其真正不安全。
塔默·斯拉什

14

这是一个完整的问题,我想很多人都没有读完直到最后:)

我在Web服务身份验证方面的经验是,人们通常会对它进行过度设计,并且问题仅与您在网页上遇到的问题相同。可能非常简单的选项包括用于登录步骤的https,返回令牌,要求将其包含在以后的请求中。您还可以使用http基本身份验证,仅在标头中传递内容。为了增强安全性,请经常旋转/过期令牌,检查请求是否来自同一IP块(尽管移动用户在单元之间移动,这可能会很混乱),并与API密钥或类似密钥结合使用。或者,在对用户进行身份验证之前,执行oauth的“请求密钥”步骤(有人已经在先前的回答中对此提出了建议,这是个好主意),并将其用作生成访问令牌的必需密钥。

我尚未使用的替代方法,但我已经听到很多关于xAuth的信息,它们是oAuth的一种设备友好的替代方法。看看它,如果您使用它,那么我真的很想听听您的印象。

对于散列,sha1更好一些,但不要挂在嘴上-无论设备可以容易地(在性能方面迅速实现),都可以。

希望有帮助,祝你好运:)


感谢您的回复。我一直在研究xAuth,这可能是我要走的路,以便最终可以进行oAuth安装,这使与API交互的过程更加标准化。
jsuggs 2010年

9

那么,您所需要的是某种服务器端身份验证机制,该机制将处理移动应用程序的身份验证和授权方面?

假设是这种情况,那么我将按以下方式进行处理(但只有'cos我是Java开发人员,因此C#的做法会有所不同):

RESTful身份验证和授权服务

  1. 这只能在HTTPS上起作用,以防止窃听。
  2. 它将基于RESTEasySpring SecurityCAS的组合(用于跨多个应用程序的单点登录)。
  3. 它将与浏览器和启用Web的客户端应用程序一起使用
  4. 将有一个基于Web的帐户管理界面,允许用户编辑其详细信息,管理员(针对特定应用程序)可以更改授权级别

客户端安全库/应用程序

  1. 对于每个受支持的平台(例如Symbian,Android,iOS等),以平台的本地语言(例如Java,ObjectiveC,C等)创建安全库的适当实现。
  2. 该库应使用给定平台的可用API管理HTTPS请求的形成(例如Java使用URLConnection等)
  3. 通用身份验证和授权库(仅此而已)的使用者将编码到特定的接口,并且一旦更改就不会满意,因此请确保它非常灵活。遵循现有的设计选择,例如Spring Security。

因此,现在从30,000英尺的角度看完整了,您如何去做呢?嗯,在服务器端使用浏览器客户端基于列出的技术创建身份验证和授权系统并不难。与HTTPS结合使用时,这些框架将基于由身份验证过程生成的共享令牌(通常表示为cookie)提供安全过程,并在用户希望做某事时使用。每当发生任何请求时,客户端都会将该令牌提供给服务器。

对于本地移动应用程序,似乎您正在寻找一种执行以下操作的解决方案:

  1. 客户端应用程序具有定义的访问控制列表(ACL),用于控制对方法调用的运行时访问。例如,给定的用户可以从方法中读取集合,但是他们的ACL仅允许访问名称中带有Q的对象,因此集合中的某些数据会被安全拦截器悄悄提取。在Java中,这很简单,您只需在调用代码上使用Spring Security批注并实现适当的ACL响应过程即可。换句话说,您是一个人,可能需要提供调用安全性库的样板安全性代码。如果语言支持AOP(面向方面​​的编程),则可以在这种情况下最大程度地使用它。
  2. 安全库将完整的授权列表缓存到当前应用程序的专用内存中,因此不必保持连接状态。根据登录会话的时间长短,这可能是一次无法重复的操作。

无论您做什么,都不要尝试发明自己的安全协议也不要盲目使用安全性。没有比现在可用和免费的算法更好的算法了。而且,人们相信众所周知的算法。因此,如果您说您的安全库使用SSL,HTTPS,SpringSecurity和AES加密令牌的组合为本地移动应用程序提供了授权和身份验证,那么您将立即在市场上享有信誉。

希望这会有所帮助,并祝您事业顺利。如果您想了解更多信息,请告诉我-我已经基于Spring Security,ACL等编写了许多Web应用程序。


谢谢,很好的信息。几个问题。首先,如果窃听是可以接受的(不确定是否是,我的应用程序中没有真正的个人/有价值的信息,但是如果我的理由会改变),那么实际上是否需要HTTPS?
jsuggs

如果愿意,您可以在HTTPS之外运行整个系统。HTTPS仅用于保护机密信息,因此我假设在身份验证阶段,您将通过HTTPS这样做,以确保您的用户名/密码/机密保持秘密。在令牌在响应中移交之后,如果流中包含的信息(需要获得身份验证)不需要进行窃听保护,则可以明确提出其他请求。
加里·罗

同样,对CAS身份验证协议的这种描述可能会很有用:jasig.org/cas/protocol
Gary Rowe 2010年

9

Twitter通过支持称为xAuth的变体来解决oAuth中的外部应用程序问题。不幸的是,已经有很多其他使用此名称的方案,因此进行分类可能会令人困惑。

该协议 oAuth,只是它跳过了请求令牌阶段,仅在收到用户名和密码后立即发出访问令牌对。(在启动步骤E中在这里。)这个初始必须确保请求和响应-它以纯文本形式发送用户名和密码,并接收访问令牌和秘密令牌。一旦配置了访问令牌对,对于会话的其余部分,最初的令牌交换是通过oAuth模型还是通过xAuth模型进行的,都与客户端和服务器无关。这样做的好处是,您可以利用现有的oAuth基础架构,并且对移动/网络/桌面应用程序的实现几乎相同。主要缺点是,该应用程序被授予了访问客户端用户名和密码的权限,但是您的要求似乎要求使用此方法。

无论如何,我想同意您的直觉以及此处的其他一些回答者的直觉:请勿尝试从头开始构建新内容。安全协议可以很容易启动,但总是很难做好,而且它们越复杂,您的第三方开发人员就越不可能针对它们实施。您的假设协议与o(x)Auth非常相似-api_key / api_secret,nonce,sha1哈希-但是开发人员将无法使用许多现有库之一来开发自己的库。


2
我还应该指出,“跳过请求令牌”端点看起来将在oAuth 2中,它在当前草案中被列为“密码”访问授权类型。请参阅第4.1.2节:tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.1.2
lantius 2010年

就像我在Lonra提到的那样,我正在研究xAuth,尤其是由于您在最后提到的原因……开发人员可以“下架” oAuth工具/库来与我的API交互,这是“一件好事” 。
jsuggs 2010年

6

派对晚了,但是我想补充一点,供对此问题感兴趣的任何人考虑。我为一家从事移动API安全解决方案的公司工作( approov)所以这整个领域绝对符合我的兴趣。

首先,在尝试保护移动API时要考虑的最重要的事情是 是对您来说有多少价值。对于银行来说,正确的解决方案不同于仅仅为了娱乐而做某事的人的正确解决方案。

在建议的解决方案中,您提到至少需要三个参数:

  • apikey-注册时提供给开发人员
  • 时间戳-兼用作给定apikey的每个消息的唯一标识符
  • hash-时间戳+ apisecret的哈希

这意味着对于某些API调用,不需要用户名/密码。这对于不想强制登录的应用程序很有用(例如,在网上商店浏览)。

这与用户身份验证的问题稍有不同,更像是软件的身份验证或证明。没有用户,但是您仍然要确保没有对API的恶意访问。因此,您可以使用API​​机密对流量进行签名,并将访问该API的代码识别为真实代码。该解决方案的潜在问题是您必须在每个版本的应用程序内都泄露秘密。如果有人可以提取秘密,那么他们可以使用您的API,从而模仿您的软件,但是可以随心所欲地进行操作。

为了应对这种威胁,您可以根据数据的价值采取一系列措施。混淆是增加密码提取难度的一种简单方法。有一些工具可以为您做到这一点,对于Android而言更是如此,但是您仍然必须拥有生成哈希的代码,并且有足够技能的人总是可以直接调用直接执行哈希的函数。

避免过度使用不需要登录的API的另一种方法是限制流量,并可能识别和阻止可疑IP地址。您要花费的精力在很大程度上取决于数据的价值。

除此之外,您还可以轻松地开始从事我的日常工作。无论如何,这是保护API的另一方面,我认为这很重要,并希望对其进行标记。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.