[英]Is OAuth 2.0 the proper tool for securing access to web service?
我打算创建两个项目。
一个项目将是一个简单的以HTML / Javascript为中心的项目,它使用AJAX从Web服务中检索和轮询数据。 我们称之为项目A.
另一个项目B项是一个RESTFul Web服务,它只是从外部源缓存数据检索。
基本上,Project B将作为一个以上项目的Web服务。 我不会向公众展示项目B. 我刚刚将项目A用作将从项目B进行轮询的示例项目。
我读过OAuth 2.0,它似乎是防止任何其他应用程序访问我的Web服务的最佳和最直接的方法。 但这里有一些问题:
这让我想问,OAuth 2.0是正确的方法吗? 或者还有其他更简单的选择吗?
与此处所说的相反:
我相信OAuth 2.0不是要走的路。
为什么?
OAuth 2.0是授权协议,而不是身份验证协议。 它依赖于第三方提供身份验证。 如果您想重新授权服务使用,第三方还会存储谁有权访问哪些资源。 因此,单凭OAuth 2.0永远无法解决任何身份验证问题。 如果您希望您的应用程序(在oauth的术语:资源服务器中)独立于提供OAuth(授权服务器)的其他第三方,您必须自己实现授权服务器。 您将拥有有限数量的资源服务器,而OAuth实际上是为了授权跨多个提供商的服务访问。 因此,我不知道OAuth如何解决您的问题。
JSONP是否安全实际上是一个有趣的问题。
实际上JSONP是什么? 这是javascript在您的DOM中添加脚本标记,并使浏览器加载该额外资源。 它是否安全基本上与要求浏览器和服务器之间的任何通信的安全性是相同的问题。 它会像你做的那样安全。 具有Access-Control-Allow-Origin等的AJAX也是如此。
那么该怎么办?
首先是一件事。 如果您的应用程序A只是静态资源,则您不需要应用程序,则需要内容交付网络。 这就是stackoverflow如何做到这一点,这就是它如何胜过你自己可以托管的任何服务器。 有这个,并有像谷歌的pagespeed缓存代理(我不知道该产品是否仍然存在,但它只是作为一个例子)。
以下是另外两个想法:
如果您希望两个应用程序之间的通信安全,则可以使用非对称加密。 交换公钥,您可以验证身份并安全地传输数据。 我会留给你深入研究此事。
同样,史蒂夫E.写道,但没有正确命名,你可以使用CSRF代币 。 我相信jQuery现在已经支持了一段时间,但是如果没有jQuery,这种技术同样适用。 再一次,这是我要让你深入研究的问题。
最后
所有这些让我想到重新发明轮子。 只要你的连接是安全的,你就可以做任何事情(包括带有reaaaaaally long字符串的纯文本身份验证),只要你有点偏执并在你的身份验证机制中加入一些熵。 那么,它有多安全? 这是一个大多数时候都回答“绝对安全”的问题,但实际上很少是真正的要求。
第1部分 。 是的,AJAX可以工作,JSONP为跨域和跨浏览器支持提供了最大的灵活性。
JSONP的工作原理是在页面标记中添加新标记,这些标记未被大多数其他请求类型强制执行的同源策略 (SOP)阻止。 'P'代表填充,指的是在Javascript函数中填充的JSON响应。 必须在客户端上执行此函数才能检索函数中嵌入的JSON数据并绕过SOP。
这样做会带来许多潜在的安全风险。 首先,它取决于浏览器运行远程服务器的代码。 如果该服务器被泄露,那么它可以将任何它喜欢的东西注入您的应用程序。 必须有远程服务器的强烈信任。
其次,在浏览器中运行的其他脚本(在其他选项卡或窗口上)也可以向远程Web服务器发出请求并窃取响应数据,因为SOP不适用于JSONP。 如果将cookie用作远程服务器的会话标识符,则更有可能。 所以你不会将它用于银行软件。
如果您的应用安全要求足够低,您可以忍受这些风险,那么JSONP将完成工作。 当您试图避免为项目A提供服务器端应用程序时。
备择方案:
现代浏览器支持跨源资源共享。 我没有用它来评论它如何满足你的需求。
使用同一域的子域来托管项目A和项目B.在此方案中,项目A可以在www.domain.com上,项目B可以在webservice.domain.com上。 如果两个子域都返回内容,例如设置'document.domain =“domain.com”'的iframe,那么他们就可以进行通信。
我不确定上述任何一种方法都适合您的场景。
第2部分。
正如所讨论的,身份验证的目的是减少第三方向您的Web服务发出请求的可能性。 为了让Project A对公众来说很容易,所有这些都需要使用Javascript。 这意味着在给定时间内,您实施的任何系统都可以进行逆向工程并且可以滥用。
项目B不能保证看似来自项目A的请求确实这样做。 但是,通过使请求机制略显模糊,您至少可以减轻自动脚本和简单攻击。 这将阻止较不确定的流氓用户。
一种选择是向项目B提供额外的初始请求。这将返回随机种子,然后由项目A和项目B使用该种子来计算使用预定公式在后续请求中使用的令牌。 任何没有允许令牌的请求都将被拒绝。 令牌可能受项目B的时间限制。项目A将在前一个种子到期时请求新种子。
知情的攻击者仍然可以打破这种机制,您需要确定该应用程序是否可以接受该风险。 令牌请求的速率限制和异常流量模式的监控也可能是谨慎的。
问题1
我不喜欢JSONP,所以在我看来,你更好的选择是让你的Proejct A服务器成为你的项目B的代理。
例如,如果您使用NodeJS和Express来提供项目A请求,则可以将所有/api
请求重定向到项目B,如下所示:
app.use('/api', function (req, res) {
req
.pipe(request('https://projectB.com/' + req.url))
.pipe(res);
});
所以你的NodeJS将处理从浏览器发出的所有请求,除了那些以/api
结尾的请求。
另一个选项是配置Project B服务器以在每个请求中发送CORS头。
例如,如果您使用的是Java,则可以创建一个servlet过滤器来添加这些标头:
@Component
public class SimpleCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");//Instead of '*' use your own domain!
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
问题2我认为OAuth 2.0似乎是您目前情况下的最佳选择。
您不应将用户密码存储在Project A应用程序中。 您的javascript应用程序应该存储一个访问令牌,而不是存储密码,该令牌将用于访问REST端点。
除了避免安全风险之外,通过使用令牌基本身份验证,您可以在用户更改密码时防止很多麻烦。
此外,您可以使用HTML 5会话存储来存储访问令牌(以及刷新令牌),因为当用户关闭浏览器时将删除此信息,并且只有从应用程序域加载的选项卡才能访问此数据。
如果您最终选择基于令牌的身份验证,则可以编写自己的实现来生成该令牌,但我认为使用众所周知的实现要好得多。 此外,有许多框架在您的服务器端以多种语言实现OAuth身份验证:Java,python,Node等...
如果您使用的是Java,看看一些例子在这里使用Spring的OAuth。
现在的问题是您更喜欢哪种授权流程?
OAuth提供了一些不同的授权流程。 根据您提供的信息,我认为最好的选择是资源所有者基于密码的授权 ,因为您的用户将信任您的JavaScript应用程序(项目A),因此他们将很容易将其凭据直接提供给您的应用程序。
注意 :如果您最终选择OAuth 2,请确保所有请求都使用HTTPS进入服务器,因为OAuth 2不包含任何有关密码的内容,因为它假设您的连接始终使用SSL。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.