RESTful Web服务 - 如何验证来自其他服务的请求?

Tom*_*mmi 115 authentication rest web-services restful-authentication client-certificates

我正在设计一个RESTful Web服务,需要用户访问,还需要其他Web服务和应用程序访问.所有传入的请求都需要进行身份验证.所有通信都通过HTTPS进行.用户身份验证将基于身份验证令牌工作,通过将用户名和密码(通过SSL连接)POST 到服务提供的/ session资源获取.

对于Web服务客户端,客户端服务后面没有最终用户.请求由计划的任务,事件或一些其他计算机操作启动.连接服务列表事先已知(显然,我猜).我该如何验证来自其他(网络)服务的这些请求?我希望身份验证过程尽可能简单地实现这些服务,但不以安全为代价.对于这样的场景,标准和最佳实践是什么?

我能想到的(或者有人向我建议的)选项:

  1. 让客户服务使用"假的"用户名和密码,并以与用户相同的方式对其进行身份验证.我不喜欢这个选项 - 它感觉不对劲.

  2. 为客户端服务分配永久应用程序ID,也可能是应用程序密钥.据我所知,这与用户名+密码相同.使用此ID和密钥,我可以验证每个请求,或创建身份验证令牌以验证进一步的请求.无论哪种方式,我都不喜欢这个选项,因为任何能够获得应用程序ID和密钥的人都可以冒充客户端.

  3. 我可以在以前的选项中添加IP地址检查.这将使执行虚假请求变得更加困难.

  4. 客户证书.设置我自己的证书颁发机构,创建根证书,并为客户端服务创建客户端证书.但是,有几个问题浮现在脑海中:a)如何在没有证书的情况下允许用户进行身份验证,以及b)从客户端服务的角度来看,这种情况有多复杂?

  5. 还有别的 - 那里必须有其他解决方案吗?

我的服务将运行在Java上,但我故意遗漏了有关它将构建的具体框架的信息,因为我对基本原则更感兴趣,而不是对实现细节更感兴趣 - 我认为最好的解决方案是无论底层框架如何,都可以实现.但是,我对这个主题有点缺乏经验,所以对实际实现的具体提示和示例(例如有用的第三方库,文章等)也将非常感激.

kor*_*oro 36

在阅读完您的问题后,我会说,生成特殊令牌以执行所需的请求.此令牌将在特定时间生效(假设在一天内).

以下是生成身份验证令牌的示例:

(day * 10) + (month * 100) + (year (last 2 digits) * 1000)
Run Code Online (Sandbox Code Playgroud)

例如:2011年6月3日

(3 * 10) + (6 * 100) + (11 * 1000) = 
30 + 600 + 11000 = 11630
Run Code Online (Sandbox Code Playgroud)

然后与用户密码连接,例如"my4wesomeP4ssword!"

11630my4wesomeP4ssword!
Run Code Online (Sandbox Code Playgroud)

然后做该字符串的MD5:

05a9d022d621b64096160683f3afe804
Run Code Online (Sandbox Code Playgroud)

你什么时候打电话请求,总是使用这个令牌,

https://mywebservice.com/?token=05a9d022d621b64096160683f3afe804&op=getdata
Run Code Online (Sandbox Code Playgroud)

这个令牌每天都是独一无二的,所以我想这种保护足以永远保护你的服务.

希望有所帮助

:)

  • 如果时钟不同步会怎么样?客户端不会在此实例中生成错误的令牌吗?即使两者都以UTC格式生成日期时间,它们的时钟仍可能不同,导致每天的时间窗口,当令牌不起作用时? (4认同)

new*_*000 34

这个问题的任何解决方案都归结为一个共同的秘密.我也不喜欢硬编码的用户名和密码选项,但它确实具有非常简单的优点.客户端证书也不错,但它真的有很大的不同吗?服务器上有一个证书,客户端上有一个证书.它的主要优点是蛮力更难.希望你有其他保护措施可以防止这种情况发生.

我认为客户证书解决方案的A点难以解决.你只需要使用一个分支.if (client side certificat) { check it } else { http basic auth }我不是Java专家,我从来没有使用它来做客户端证书.然而,一个快速的谷歌引导我们到这个教程,它看起来就在你的小巷.

尽管所有这些都是"最好的"讨论,但我要指出的是,还有另一种理念,即"代码越少,聪明程度越低越好".(我个人持这种理念).客户端证书解决方案听起来像很多代码.

我知道您对OAuth表达了疑问,但OAuth2提案确实包含了一个名为" bearer tokens "的问题解决方案,必须与SSL结合使用.我认为,为了简单起见,我选择硬编码的用户/密码(每个应用程序一个,以便它们可以单独撤销)或非常相似的承载令牌.

  • 客户端证书不是共享密钥.这就是他们存在的原因.客户端具有私钥,服务器具有公钥.客户永远不会分享它的秘密,公钥也不是秘密. (27认同)
  • 教程链接不会导致教程文章,而是Oracle网站上的某些Java索引页面... (5认同)
  • @MarjanVenema嗯,那是因为你在newz2000回答后的2年内尝试了这个链接,但是你可以随时尝试使用WayBack Machine:http://web.archive.org/web/20110826004236/http://java.sun.com /开发/ technicalArticles /安全/ secureinternet2 / (2认同)
  • @FábioSilva:不,我没有_期待他这样做.我确实阅读了档案,但我没有时间去寻找新的链接,所以我做了下一个最好的事情:发表评论说它已经死了,所以社区中的其他人可以找到新的位置并更新帖子.由于您显然有时间找到新链接,为什么不更新帖子中的链接而不是将其放在评论中? (2认同)

jwi*_*mar 11

您可以采取几种不同的方法.

  1. RESTful纯粹主义者希望您使用BASIC身份验证,并在每个请求上发送凭据.他们的理由是没有人存储任何国家.

  2. 客户端服务可以存储cookie,该cookie维护会话ID.我个人认为这不像我听到的一些纯粹主义者那样令人反感 - 一遍又一遍地认证可能是昂贵的.不过,听起来你并不是太喜欢这个想法.

  3. 根据你的描述,听起来你可能对OAuth2感兴趣.到目前为止,我的经验,从我所看到的,是它有点令人困惑,有点出血.那里有实现,但它们很少而且很远.在Java中,我知道它已经集成到Spring3的安全模块中.(他们的教程编写得非常好.)我一直在等待Restlet中是否会有扩展,但到目前为止,虽然它已被提出,并且可能在孵化器中,但它仍未完全合并.