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

jsu*_*ggs 187 authentication api rest oauth mobile-application

概观

我正在寻找为我的应用程序创建(REST)API.初始/主要目的是供移动应用程序(iPhone,Android,Symbian等)使用.我一直在研究基于Web的API的身份验证和授权的不同机制(通过研究其他实现).我已经掌握了大部分基本概念,但我仍在寻找一些领域的指导.我想做的最后一件事就是重新发明轮子,但我找不到任何符合我标准的标准解决方案(不过我的标准是我的误导,所以也可以随意批评).此外,我希望API对于使用它的所有平台/应用程序都是相同的.

OAuth的

我会继续向oAuth抛弃我的反对意见,因为我知道这可能是第一个提供的解决方案.对于移动应用程序(或更具体地说是非Web应用程序),离开应用程序(转到Web浏览器)进行身份验证似乎是错误的.此外,没有办法(我知道)浏览器将回调返回给应用程序(特别是跨平台).我知道有几个应用程序可以做到这一点,但它只是感觉不对,并且在应用程序用户体验中取得了突破.

要求

  1. 用户在应用程序中输入用户名/密码
  2. 每个API调用都由调用应用程序标识.
  3. 开销保持在最低限度,auth方面对开发人员来说非常直观.
  4. 该机制对于最终用户(他们的登录凭证未公开)以及开发人员(他们的应用程序凭证未公开)都是安全的.
  5. 如果可能,不要求https(绝不是硬性要求).

我目前对实施的看法

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

  • apikey - 在注册时交给开发人员
  • timestamp - 兼作给定apikey的每条消息的唯一标识符
  • hash - 时间戳的哈希值+ apisecret

需要apikey来识别发出请求的应用程序.时间戳的作用与oauth_nonce类似,可以避免/减轻重放攻击.哈希确保请求实际是从给定apikey的所有者发出的.

对于经过身份验证的请求(代表用户完成的请求),我仍然未决定使用access_token路由或用户名和密码哈希组合.无论哪种方式,在某些时候都需要用户名/密码组合.因此,当它发生时,将使用几条信息(apikey,apisecret,timestamp)+密码的散列. 我喜欢这方面的反馈. 仅供参考,他们必须首先对密码进行哈希处理,因为我没有在没有散列的情况下将密码存储在我的系统中.

结论

仅供参考,这不是要求如何构建/构建API,一般只是如何仅在应用程序内处理身份验证和授权.

随机思考/奖金问题

对于只需要apikey作为请求的一部分的API,如何防止apikey所有者以外的其他人能够看到apikey(因为明确发送)并过多地请求推送它们超过使用限制?也许我只是在想这个,但是不应该有一些东西需要验证是否已向apikey所有者验证了请求?在我的情况下,这是apisecret的目的,它不会被显示/传输而不被散列.

说到哈希,md5和hmac-sha1怎么样?当所有值都用足够长的数据(即apisecret)进行散列时,这真的很重要吗?

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

Mic*_*son 43

我正在考虑在我的项目中执行此登录部分的方式是:

  1. 在登录之前,用户login_token从服务器请求a .这些是根据请求生成并存储在服务器上的,并且可能具有有限的生命周期.

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

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

这样做的好处是你永远不会将用户的密码存储在服务器上,密码永远不会以明文形式传递,密码哈希只会在明确的帐户创建中传递(虽然可能有办法解决这个问题),它应该是免受重放攻击,因为它login_token在使用时从数据库中删除.

  • 我看到了这种方法的缺点:你不能在DB中存储盐渍密码.如果攻击者将手放在您的数据库上,他们就不需要进行任何解密.由于密码哈希是此方案中的真实密码. (2认同)
  • @sigod你是对的.虽然我认为那里有一个基本的二分法 - 你需要相信你的交通工具,或者你需要相信你的存储.使用加密密码的登录系统信任传输层 - 因此将密码从用户传递到身份验证系统中.这种情况不信任传输层(我认为这是因为我所针对的平台对SHTTP的支持不好).如果您信任传输层,则可以进行其他权衡. (2认同)

Lor*_*ell 13

这是一个很多问题,我想很多人没有设法一直读到最后:)

我对Web服务身份验证的体验是,人们通常会过度使用它,而且问题只与您在网页上遇到的问题相同.可能非常简单的选项包括登录步骤的https,返回令牌,要求将其包含在将来的请求中.您还可以使用http基本身份验证,只需传递标题中的内容即可.为了增加安全性,请经常旋转/过期令牌,检查请求是否来自同一个IP块(这可能会因为移动用户在小区之间移动而变得混乱),与API密钥或类似组合.或者,在对用户进行身份验证之前,执行oauth的"请求密钥"步骤(有人在之前的回答中建议这一点并且这是一个好主意),并将其用作生成访问令牌的必需密钥.

我还没有使用的另一种选择,但我听说过很多关于作为oAuth的设备友好替代品的是xAuth.看看它,如果你使用它,那么我真的很想知道你的印象是什么.

对于散列,sha1稍微好一点,但不要挂断它 - 无论设备如何轻松(并且在性能意义上很快)实现可能都没问题.

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


lan*_*ius 9

Twitter通过支持他们称之为xAuth的变体来解决oAuth中的外部应用程序问题.不幸的是,已有大量其他具有此名称的方案,因此可能会让人感到困惑.

协议 oAuth,除了它跳过请求令牌阶段并且在收到用户名和密码后立即发出访问令牌对.(从此处的步骤E开始.)必须保证初始请求和响应 - 它以明文形式发送用户名和密码,并接收访问令牌和秘密令牌.一旦配置了访问令牌对,初始令牌交换是通过oAuth模型还是xAuth模型与会话其余部分的客户端和服务器无关.这样做的好处是,您可以利用现有的oAuth基础架构,并为移动/ Web /桌面应用程序提供几乎相同的实现.主要的缺点是应用程序被授予访问客户端用户名和密码的权限,但看起来您的要求强制要求这种方法.

在任何情况下,我都同意你的直觉以及其他几个回答者的直觉:不要试图从头开始构建新东西.安全协议可以很容易地启动,但总是很难做到,并且它们变得越复杂,第三方开发人员就越不可能实现它们.您的假设协议非常类似于o(x)Auth - api_key/api_secret,nonce,sha1哈希 - 但是您可以使用许多现有库中的一个,而您的开发人员将需要自己编写这些库.

  • 我还应该指出,看起来"跳过请求令牌"端点将在oAuth 2中,它在当前草案中列为"密码"访问授权类型.见4.1.2节:http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.1.2 (2认同)

Gar*_*owe 8

那么你所追求的是某种服务器端认证机制,它将处理移动应用程序的身份验证和授权方面?

假设是这种情况,那么我会按如下方式处理它(但只是'我是Java开发人员所以C#的人会以不同的方式做到这一点):

RESTful身份验证和授权服务

  1. 这仅适用于HTTPS以防止窃听.
  2. 它将基于RESTEasy,Spring SecurityCAS的组合(用于跨多个应用程序的单点登录).
  3. 它适用于浏览器和支持Web的客户端应用程序
  4. 将有一个基于Web的帐户管理界面,允许用户编辑他们的详细信息,以及管理员(针对特定应用程序)更改授权级别

客户端安全库/应用程序

  1. 对于每个支持的平台(例如Symbian,Android,iOS等),以平台的本机语言(例如Java,ObjectiveC,C等)创建合适的安全库实现
  2. 库应该使用给定平台的可用API来管理HTTPS请求的形成(例如,Java使用URLConnection等)
  3. 一般认证和授权库的消费者('cos就是这样)将编码到特定的界面,如果它发生变化就不会高兴,所以要确保它非常灵活.遵循现有的设计选择,例如Spring Security.

那么现在30,000英尺的视图已经完成了你怎么去做呢?嗯,使用浏览器客户端在服务器端基于列出的技术创建身份验证和授权系统并不困难.与HTTPS结合使用时,框架将基于由身份验证过程生成的共享令牌(通常表示为cookie)提供安全过程,并在用户希望执行某些操作时使用.无论何时发生任何请求,客户端都会将此令牌呈现给服务器.

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

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

无论你做什么,都不要试图发明自己的安全协议,或者通过默默无闻来使用安全性.你永远无法为此编写一个比当前可用且免费的算法更好的算法.此外,人们相信众所周知的算法.因此,如果您说安全库使用SSL,HTTPS,SpringSecurity和AES加密令牌的组合为本地移动应用程序提供授权和身份验证,那么您将立即在市场中获得信誉.

希望这会有所帮助,并祝你好运.如果您想了解更多信息,请告诉我 - 我已经编写了很多基于Spring Security,ACL等的Web应用程序.


The*_*ist 6

超级晚会,但我想为任何对此问题感兴趣的人提出一些额外的要点.我在一家公司从事移动API安全解决方案(approov)的工作,因此整个领域与我的兴趣无关.

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

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

  • apikey - 在注册时交给开发人员
  • timestamp - 兼作给定apikey的每条消息的唯一标识符
  • hash - 时间戳的哈希值+ apisecret

这意味着对于某些API调用,不需要用户名/密码.这对于您不想强制登录的应用程序非常有用(例如,在在线商店中浏览).

这与用户身份验证的问题略有不同,更像是软件的身份验证或证明.没有用户,但您仍希望确保您的API没有恶意访问权限.因此,您使用API​​密钥对流量进行签名,并将访问API的代码标识为正版.这个解决方案的潜在问题是你必须在每个版本的应用程序中泄露秘密.如果有人可以提取秘密,他们可以使用您的API,冒充您的软件,但做任何他们喜欢的事情.

为了应对这种威胁,根据数据的价值,你可以做很多事情.混淆是一种简单的方法,可以更难以提取秘密.有一些工具可以帮到你,对Android来说更是如此,但是你仍然必须拥有生成哈希的代码,并且一个技术娴熟的人总是可以直接调用执行哈希的函数.

另一种减轻过度使用不需要登录的API的方法是限制流量并可能识别和阻止可疑的IP地址.您想要的努力程度在很大程度上取决于您的数据的价值.

除此之外,您可以轻松地开始进入我的日常工作领域.无论如何,这是保护API的另一个方面,我认为这很重要并且想要标记.