REST风格的Web服务 – 如何authentication来自其他服务的请求?
我正在devise一个需要被用户访问的REST风格的Web服务,也包括其他Web服务和应用程序。 所有传入的请求都需要进行身份validation。 所有通信都通过HTTPS进行。 用户authentication将基于通过将用户名和密码(通过SSL连接)发布到由服务提供的/会话资源而获取的authentication令牌来工作。
在Web服务客户端的情况下,在客户端服务之后没有最终用户 。 这些请求由计划的任务,事件或一些其他计算机操作启动。 连接服务列表事先已知(显然,我猜)。 我应该如何validation来自其他(networking)服务的这些请求? 我希望validation过程尽可能容易地实现这些服务,但不以安全为代价。 这样的场景的标准和最佳实践是什么?
我可以想到的选项(或者已经向我build议):
-
让客户端服务使用“假”用户名和密码,并以与用户相同的方式对其进行身份validation。 我不喜欢这个选项 – 只是觉得不对。
-
为客户端服务分配永久的应用程序ID,也可能是应用程序密钥。 据我了解,这是有相同的用户名+密码。 有了这个ID和密钥,我可以对每个请求进行身份validation,或者创build一个身份validation令牌来validation进一步的请求。 无论哪种方式,我不喜欢这个选项,因为任何能够获得应用程序ID和密钥的人都可以模拟客户端。
-
我可以添加一个IP地址检查到以前的选项。 这将使得执行虚假请求变得更困难。
-
客户端证书。 设置我自己的证书颁发机构,创build根证书,并为客户机服务创build客户机证书。 但是,有几个问题想到:a)如何仍然允许用户在没有证书的情况下进行身份validation; b)从客户端服务的angular度来看,这种情况有多复杂?
-
还有其他的东西 – 那里必须有其他的解决scheme吗?
我的服务将运行在Java上,但是我特意留下了关于它将构build的具体框架的信息,因为我对基本原则更感兴趣,而不是更多地关注实现细节 – 我认为这是最好的解决scheme无论底层框架如何,都可以实现。 不过,我对这个主题有点不熟悉,所以对于实际实现(如有用的第三方库,文章等)的具体提示和例子也将非常感激。
任何解决这个问题的办法都归结为一个共同的秘密。 我也不喜欢硬编码的用户名和密码选项,但它确实有很简单的好处。 客户证书也不错,但真的有很大的不同吗? 服务器上有一个证书,客户机上有一个证书。 它的主要优点是难于暴力。 希望你有其他的保护,以防止这种情况。
我不认为你的客户端证书解决schemeA是难以解决的。 你只是使用一个分支。 if (client side certificat) { check it } else { http basic auth }
我不是Java专家,我从来没有与它合作做客户端证书。 然而,一个快速的谷歌引导我们看这个教程 ,看起来你的胡同。
尽pipe所有这些都是“最好的”讨论,但我还是要指出,还有另外一个哲学,即“less编码,less聪明就好”。 (我个人认为这个哲学)。 客户端证书解决scheme听起来像很多代码。
我知道您expression了有关OAuth的问题,但OAuth2提案确实包含了一个解决scheme,称为“ 持票人令牌 ”,必须与SSL一起使用。 我想,为了简单起见,我会select硬编码的用户/密码(每个应用程序一个,以便可以单独撤销)或非常相似的持证人代币。
读完你的问题后,我会说,生成特殊的令牌来做请求。 这个令牌将在特定的时间生活(可以说在一天之内)。
以下是生成身份validation令牌的示例:
(day * 10) + (month * 100) + (year (last 2 digits) * 1000)
例如:2011年6月3日
(3 * 10) + (6 * 100) + (11 * 1000) = 30 + 600 + 11000 = 11630
然后连接用户密码,例如“my4wesomeP4ssword!”
11630my4wesomeP4ssword!
然后做那个string的MD5:
05a9d022d621b64096160683f3afe804
你什么时候调用请求,总是使用这个令牌,
https://mywebservice.com/?token=05a9d022d621b64096160683f3afe804&op=getdata
这个令牌每天都是独一无二的,所以我想这种保护绰绰有余,总是保护我们的服务。
希望有帮助
🙂
有几种不同的方法可以采取。
-
RESTful纯粹主义者会希望您使用BASIC身份validation,并在每个请求上发送凭据。 他们的理由是,没有人存储任何国家。
-
客户端服务可以存储一个cookie,它维护一个会话ID。 我个人认为这不像我听到的一些纯粹主义者那样冒犯 – 一遍又一遍的validation可能是昂贵的。 听起来好像你不太喜欢这个想法。
-
从你的描述来看,这听起来好像你可能对OAuth2感兴趣。从我所见到的情况来看,迄今为止,我的经验是有点混乱,而且有点出血。 那里有一些实现,但是它们很less。 在Java中,我明白它已经被集成到Spring3的安全模块中。 (他们的教程写得很好。)我一直在等待Restlet中是否会有扩展,但是到目前为止,虽然已经提出,并且可能在孵化器中,但是还没有完全纳入。
我相信这个办法:
- 第一个请求,客户端发送ID /密码
- 交换身份证/传递唯一标记
- 在每个后续请求上validation令牌,直到过期
是非常标准的,不pipe你如何实现和其他具体的技术细节。
如果你真的想要推动信封,也许你可以把客户端的https密钥视为暂时无效的状态,直到证书被validation,如果永远不会有信息,那么在validation时授予访问权限。
希望这可以帮助
就客户端证书方式而言,实施起来并不难,但仍然允许没有客户端证书的用户使用。
如果您确实创build了自己的自签名证书颁发机构,并为每个客户机服务颁发了客户机证书,那么您就可以轻松validation这些服务。
根据您使用的Web服务器,应该有一个方法来指定将接受客户端证书的客户端身份validation,但不需要一个。 例如,在Tomcat中指定https连接器时,可以设置'clientAuth = want',而不是'true'或'false'。 然后,确保将自己签名的CA证书添加到信任库(默认情况下,您正在使用JRE中的cacerts文件,除非您在Web服务器configuration中指定了另一个文件),所以唯一的可信证书是那些颁发你自己签名的CA.
在服务器端,如果您能够从请求(非空)中检索客户端证书,则只允许访问您希望保护的服务,并且如果您希望获得任何额外的安全性,则会通过任何DN检查。 对于没有客户端证书的用户,他们仍然可以访问您的服务,但在请求中没有任何证书。
在我看来,这是最“安全”的方式,但它肯定有其学习曲线和开销,因此可能不一定是您需要的最佳解决scheme。
5.其他的东西 – 那里一定有其他的解决scheme吗?
你是对的,有! 它被称为JWT(JSON Web Tokens)。
JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一个紧凑且自包含的方式,用于在各方之间以JSON对象安全地传输信息。 这些信息可以通过数字签名进行validation和信任。 可以使用秘密(使用HMACalgorithm)或使用RSA的公钥/私钥对来对JWT进行签名。
我强烈build议调查智威汤逊。 与其他解决scheme相比,这是一个更简单的解决scheme。
您可以在服务器上创build会话,并在每个REST调用中在客户端和服务器之间共享sessionId
。
-
首先validationREST请求:
/authenticate
。 使用sessionId: ABCDXXXXXXXXXXXXXX
返回响应(按照您的客户端格式)sessionId: ABCDXXXXXXXXXXXXXX
; -
将这个
sessionId
存储在实际会话的Map
。Map.put(sessionid, session)
或使用SessionListener
为你创build和销毁密钥;public void sessionCreated(HttpSessionEvent arg0) { // add session to a static Map } public void sessionDestroyed(HttpSessionEvent arg0) { // Remove session from static map }
-
获取每个REST调用sessionid,如
URL?jsessionid=ABCDXXXXXXXXXXXXXX
(或其他方式); - 使用
sessionId
从地图返回HttpSession
; - 如果会话处于活动状态,则validation该会话的请求;
- 发回回应或错误讯息。
我将使用一个应用程序将用户redirect到您的网站与一个应用程序ID参数,一旦用户批准请求生成一个唯一的令牌,由另一个应用程序用于身份validation。 这样,其他应用程序不处理用户凭据,其他应用程序可以添加,删除和用户pipe理。 Foursquare和其他一些网站以这种方式进行身份validation,并且与其他应用程序一样易于实现。
除了validation之外,我build议你想想大局。 考虑让您的后端RESTful服务没有任何身份validation; 然后在最终用户和后端服务之间放置一些非常简单的身份validation所需的中间层服务。