REST API基于令牌的身份验证

can*_*lin 121 authentication rest

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

这真的比仅要求客户端在每个请求上使用HTTP Basic Auth并缓存对身份验证服务端的调用更好吗?

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

目前令牌是这样获得的:

curl -X POST localhost/token --data "api_key=81169d80...
                                     &verifier=2f5ae51a...
                                     &timestamp=1234567
                                     &user=foo
                                     &pass=bar"
Run Code Online (Sandbox Code Playgroud)

api_key,timestamp并且verifier被所有请求所需."验证者"由以下人员返回:

sha1(timestamp + api_key + shared_secret)
Run Code Online (Sandbox Code Playgroud)

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

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

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

curl localhost/posts?api_key=81169d80...
                    &verifier=81169d80...
                    &token=9fUyas64...
                    &timestamp=1234567
Run Code Online (Sandbox Code Playgroud)

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

cmc*_*cmc 94

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

认证

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

验证服务器负载

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

传输安全

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

url = username:key@myhost.com/api/call/nonce
Run Code Online (Sandbox Code Playgroud)

如果这是不可能的,并且传输的信息不是秘密的,我建议使用哈希来保护请求,正如您在令牌方法中所建议的那样.由于哈希提供了安全性,因此您可以指示用户提供哈希作为基本密码.为了提高稳健性,我建议使用随机字符串而不是时间戳作为"随机数"来防止重放攻击(在同一秒内可以进行两次合法请求).您可以简单地使用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
Run Code Online (Sandbox Code Playgroud)

确实,这有点费力.这是因为您没有使用协议级解决方案(如SSL).因此,向用户提供某种SDK可能是个好主意,因此至少他们不必自己完成.如果你需要这样做,我发现安全级别合适(刚刚 - 右杀).

安全的秘密存储

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

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

(*)编辑: 如果采取额外步骤来验证 SSL连接,则不应再将 SSL连接视为安全连接.


Rub*_*mes 16

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

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

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

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

我为Cisco Prime Performance Manager应用程序开发了RESTful服务.谷歌搜索,我写了该应用程序有关REST风格的API合规性详细信息的REST API文档在这里.在该实现中,我选择使用HTTP"基本"授权方案. - 查看该REST API文档的1.5或更高版本,并在文档中搜索授权.

  • -1"任何技巧,例如基于令牌的身份验证,试图记住服务器上先前REST请求的状态,都违反了REST原则."**基于令牌的身份验证与先前REST请求的状态无关,并且不违反REST**的无状态. (12认同)
  • _"添加新的HTTP标头违反了REST原则"_怎么做?如果你在这里,你可能会非常友好地解释在一段时间后过期的密码与在一段时间后过期的令牌之间的差异(关于原则). (8认同)
  • 用户名+密码是在每个请求上在客户端和服务器之间交换的令牌(!).该令牌在服务器上维护并具有生存时间.如果密码过期,我必须获得一个新密码.您似乎将"令牌"与"服务器会话"相关联,但这是无效的结论.它甚至无关紧要,因为它将是一个实现细节.除了用户名/密码之外,您对令牌的分类是有状态的,纯粹是人为的,imho. (6认同)