REST API令牌

我正在开发一个需要认证的REST API。 由于认证本身通过HTTP上的外部Web服务发生,因此我推断我们会分配令牌以避免重复调用认证服务。 这使我很好地回答我的第一个问题:

这真的比仅仅要求客户端对每个请求使用HTTP Basic Auth并将认证服务缓存到服务器端更好吗?

基本身份验证解决方案的优点是在请求内容可以开始之前不需要完整的往返服务器。 令牌可能在范围上更具灵活性(即,仅授予特定资源或操作的权限),但对于OAuth上下文来说,这似乎比我的更简单的用例更合适。

目前令牌是这样获得的:

curl -X POST localhost/token --data "api_key=81169d80...
                                     &verifier=2f5ae51a...
                                     &timestamp=1234567
                                     &user=foo
                                     &pass=bar"

所有请求都需要api_keytimestampverifier 。 “验证者”由以下人员返回:

sha1(timestamp + api_key + shared_secret)

我的意图是只允许来自已知方的呼叫,并防止呼叫被逐字地重复使用。

这够好吗? 漏杀? 矫枉过正?

使用令牌时,客户可以获取资源:

curl localhost/posts?api_key=81169d80...
                    &verifier=81169d80...
                    &token=9fUyas64...
                    &timestamp=1234567

为了尽可能简单的调用,这似乎有点可怕。 考虑到shared_secret会被嵌入(至少)嵌入iOS应用程序中,我认为这个应用程序可以被提取出来,甚至可以提供任何超出虚假安全感的东西吗?


让我把所有问题分开来解决每个问题:

认证

对于身份验证,baseauth的优势在于它是协议级别的成熟解决方案。 这意味着很多“以后可能出现”的问题已经为您解决了。 例如,用BaseAuth,用户代理知道密码是一个密码,所以他们不会缓存它。

Auth服务器负载

如果向用户分配令牌而不是在服务器上缓存身份验证,则仍然执行相同的操作:缓存身份验证信息。 唯一的区别是您将缓存的责任转交给用户。 这对用户来说似乎是不必要的劳动,所以我建议按照您的建议在服务器上透明地处理这个问题。

传输安全

如果可以使用SSL连接,这就是它的全部,连接是安全的*。 为了防止意外的多次执行,您可以过滤多个URL或要求用户在URL中包含随机组件(“随机数”)。

url = username:key@myhost.com/api/call/nonce

如果这是不可能的,并且传输的信息不是秘密的,我建议使用散列来保护请求,正如您在令牌方法中所建议的那样。 由于散列提供了安全性,因此可以指示用户提供散列作为baseauth密码。 为了提高健壮性,我建议使用随机字符串而不是时间戳作为“随机数”来防止重放攻击(可能在同一秒内发出两个合法请求)。 除了提供单独的“共享密钥”和“api密钥”字段,您可以简单地将api密钥用作共享密钥,然后使用不改变的盐来防止彩虹表攻击。 用户名字段看起来是一个放置随机数的好地方,因为它是auth的一部分。 所以现在你有这样一个干净的电话:

nonce = generate_secure_password(length: 16);
one_time_key = nonce + '-' + sha1(nonce+salt+shared_key);
url = username:one_time_key@myhost.com/api/call

这确实是有点费劲。 这是因为您没有使用协议级解决方案(如SSL)。 因此,为用户提供某种SDK可能是一个好主意,因此至少他们不必亲自去完成。 如果您需要这样做,我会发现适当的安全级别(恰到好处)。

安全的秘密存储

这取决于你试图挫败谁。 如果您阻止访问用户手机的用户使用用户名中的REST服务,那么在目标操作系统上找到某种类型的keyring API并让SDK(或实现者)存储关键在那里。 如果这是不可能的,你至少可以通过加密来获得秘密,并将加密数据和加密密钥存储在不同的位置,这样做有点难。

如果您试图阻止其他软件供应商获得您的API密钥来阻止替代客户端的开发,那么只有加密和存储分离方法几乎可行。 这是白盒加密,到目前为止,还没有人提出真正安全的解决方案来解决这类问题。 您至少可以为每个用户发放一个密钥,以便您可以禁止滥用的密钥。

(*)编辑: SSL连接不应该被认为是安全的,如果没有采取额外的步骤来验证它们。


纯粹的RESTful API应该使用底层协议标准功能:

  • 对于HTTP,RESTful API应该符合现有的HTTP标准头。 添加新的HTTP头违反了REST原则。 不要重新发明轮子,使用HTTP / 1.1标准中的所有标准功能 - 包括状态响应代码,标题等等。 RESTFul Web服务应该利用和依赖HTTP标准。

  • RESTful服务必须是无状态的。 任何技巧,例如试图记住服务器上先前REST请求状态的基于令牌的认证都违反了REST原则。 再次,这是一个必须; 也就是说,如果您的Web服务器在服务器上保存任何与请求/响应上下文相关的信息,以尝试在服务器上建立任何类型的会话,那么您的Web服务不是无状态的。 如果它不是无状态的,它不是RESTFULL。

  • 底线:为了进行认证/授权,您应该使用HTTP标准授权标头。 也就是说,您应该在每个需要进行身份验证的后续请求中添加HTTP授权/身份验证标头。 REST API应遵循HTTP认证方案标准。该标题应该如何格式化的细节在RFC 2616 HTTP 1.1标准中定义 - 14.8节授权RFC 2616,以及RFC 2617 HTTP认证:基本和摘要访问认证。

    我为Cisco Prime Performance Manager应用程序开发了一个RESTful服务。 在Google上搜索我为该应用程序编写的REST API文档,以获取有关RESTFul API合规性的更多详细信息。 在那个实现中,我选择了使用HTTP“基本”授权方案。 - 检出1.5版或更高版本的REST API文档,并在文档中搜索授权。


    在Web中,一个有状态的协议基于每个请求都有一个在浏览器和服务器之间交换的临时令牌(通过Cookie头或URI重写)。 该令牌通常在服务器端创建,它是一种具有一定生存时间的不透明数据,它的唯一目的是识别特定的Web用户代理。 也就是说,令牌是临时的,并且成为Web服务器在对话期间代表客户端用户代理维护的状态。 因此,以这种方式使用令牌的通信是STATEFUL。 如果客户端和服务器之间的对话是STATEFUL,它不是RESTful。

    用户名/密码(在授权标头上发送)通常会保留在数据库中,目的是识别用户。 有时用户可能意味着另一个应用程序 但是,用户名/密码永远不会用于识别特定的Web客户端用户代理。 Web代理和服务器之间的基于使用Authorization头中的用户名/密码(在HTTP基本授权之后)的对话是STATELESS,因为Web服务器前端不代表特定的Web创建或维护任何STATE信息客户端用户代理。 根据我对REST的理解,协议明确指出客户端和服务器之间的对话应该是STATELESS。 因此,如果我们想要一个真正的RESTful服务,我们应该在每个单独调用的Authorization头中使用用户名/密码(请参阅我以前的帖子中提到的RFC),而不是感觉类型的令牌(例如,在Web服务器中创建会话令牌,授权服务器中创建的OAuth令牌等)。

    据我所知,有几个名为REST提供者正在使用令牌,如OAuth1或OAuth2接受令牌作为HTTP头中的“Authorization:Bearer”传递。 但是,在我看来,将这些令牌用于RESTful服务会违反REST所支持的真正的STATELESS含义; 因为这些令牌是服务器端创建/维护的临时数据段,用于在该Web客户端/服务器对话的有效持续时间内识别特定的Web客户端用户代理。 因此,如果我们想坚持STATELESS协议的TRUE含义,那么任何使用这些OAuth1 / 2令牌的服务都不应该被称为REST。

    鲁本斯

    链接地址: http://www.djcxy.com/p/3801.html

    上一篇: REST API Token

    下一篇: XMLHttpRequest SOAP request with Windows Authentication