首页 文章

REST API基于令牌的身份验证

提问于
浏览
114

我正在开发一个需要身份验证的REST API . 因为身份验证本身是通过HTTP上的外部Web服务发生的,所以我推断我们会分配令牌以避免重复调用身份验证服务 . 这让我整整地回答了我的第一个问题:

Is this really any better than just requiring clients to use HTTP Basic Auth on each request and caching calls to the authentication service server-side?

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

目前令牌是这样获得的:

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

所有请求都需要 api_keytimestampverifier . "verifier"由以下方式返回:

sha1(timestamp + api_key + shared_secret)

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

Is this good enough? Underkill? Overkill?

有了令牌,客户可以获得资源:

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

对于最简单的呼叫,这似乎有点可怕 . 考虑到 shared_secret 将最终嵌入(至少)一个iOS应用程序,我认为它可以从中提取出来,这甚至提供了一种超出虚假安全感的东西吗?

3 回答

  • 2

    让我分开一切,孤立地解决每个问题:

    Authentication

    对于身份验证,baseauth的优势在于它是协议级别的成熟解决方案 . 这意味着很多"might crop up later"问题已经为您解决了 . 例如,使用BaseAuth,用户代理知道密码是密码,因此他们不会对其进行缓存 .

    Auth server load

    如果您向用户分配令牌而不是在服务器上缓存身份验证,您仍然在做同样的事情:缓存身份验证信息 . 唯一的区别是您正在将缓存的责任转交给用户 . 对于没有收益的用户而言,这似乎是不必要的劳动,因此我建议您按照建议在服务器上透明地处理此问题 .

    Transmission Security

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

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

    如果这是不可能的,并且传输的信息不是秘密的,我建议使用哈希来保护请求,正如您在令牌方法中所建议的那样 . 由于哈希提供了安全性,因此您可以指示用户提供哈希作为基本密码 . 为了提高稳健性,我建议使用随机字符串而不是时间戳作为“随机数”来防止重放攻击(可以在同一秒内进行两次合法请求) . 您可以简单地使用api密钥作为共享密钥,而不是提供单独的“共享密钥”和“api密钥”字段,然后使用不会更改的salt来防止彩虹表攻击 . 用户名字段似乎也是放置nonce的好地方,因为它是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可能是一个好主意,因此至少他们不必自己完成它 . 如果你需要这样做,我发现安全级别合适(刚刚 - 右杀) .

    Secure secret storage

    这取决于你试图阻挠的人 . 如果您阻止访问用户手机的用户以用户名使用您的REST服务,那么最好在目标操作系统上找到某种密钥环API并让SDK(或实现者)存储关键在那里 . 如果这是不可能的,那么至少可以通过加密来保密,并将加密数据和加密密钥存储在单独的地方 .

    如果您试图阻止其他软件供应商获取您的API密钥以阻止备用客户端的开发,那么只有加密和存储分离方法几乎可以正常工作 . 这是whitebox加密,到目前为止,还没有人能够为这类问题找到真正安全的解决方案 . 您至少可以为每个用户发出一个密钥,因此您可以禁止滥用密钥 .

    (*) EDIT: SSL连接should no longer be considered secure没有taking additional steps to verify它们 .

  • 90

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

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

    • RESTful服务必须是无状态的 . 尝试记住服务器上先前REST请求状态的任何技巧(例如基于令牌的身份验证)都违反了REST原则 . 再一次,这是必须的;也就是说,如果你是网络服务器在服务器上保存任何请求/响应上下文相关信息,以尝试在服务器上 Build 任何类型的会话,然后您的Web服务不是无状态的 . 如果它不是无状态,那么它不是RESTFul .

    底线:出于身份验证/授权目的,您应该使用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合规性的更多详细信息here . 在该实现中,我选择使用HTTP "Basic"授权方案 . - 查看该REST API文档的1.5或更高版本,并在文档中搜索授权 .

  • 16

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

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

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

    鲁本斯

相关问题