为什么WebSockets没有同源策略?为什么我可以连接到ws:// localhost?


84

我想将WebSockets用于我的应用程序的进程间通信(Daemon <-> WebGUI和Daemon <-> FatClient等)。在测试期间,我尝试通过websocket.org(http://www.websocket.org/echo.html)上的JavaScript WebSocket客户端连接到本地运行的Web套接字服务器(ws:// localhost:1234 )。

我现在的问题是:
为什么会这样?浏览器(在Linux:FF29)上没有实现跨域策略吗?

我问是因为websocket.org如果是邪恶的,它可能会尝试与我的本地WS服务器通信并将从本地主机收到的每条消息重定向到其他任何服务器:

本地WebSocket服务器浏览器Evil Web服务器
在ws:// localhost:1234在http://evil.tld
        | | |
        | | ------ [GET /] ---------> |
        | | <----- [HTML + EvilJS] ---- |
        | <------ [连接ws:// ..] ---- | |
        | <---- [一些通讯]-> | |
        | | ---- [邪恶前进] ----> |
        | | |

我还没有测试整个用例,但是从websocket.org提供的JS连接到ws:// localhost肯定可以。


2
websocket.org不应该是邪恶的,Web套接字可以是;)
kuldeep.kamboj 2014年

Answers:


51

解决“为什么?” 部分原因是,浏览器不对WebSocket实施与AJAX调用相对的同源策略(CORS是放宽的),这是因为WebSocket是在建立跨域请求的值之后引入的,并且不必遵循SOP,CORS客户端检查的历史原因不适用。

对于AJAX,在全面单一来源策略的时代,服务器从未期望经过身份验证的浏览器从其他域发送请求1,因此不需要确保请求来自受信任的位置2,只需检查会话Cookie。后来,像CORS这样的放松措施,必须进行客户端检查,以避免违反该假设(有效地进行CSRF攻击而使现有应用程序遭受滥用

如果今天发明了Web,并且知道我们现在所知道的知识,那么AJAX既不需要SOP也不需要CORS,并且所有验证都可能留给服务器。

WebSockets是一种较新的技术,旨在从一开始就支持跨域方案。任何编写服务器逻辑的人都应意识到跨域请求的可能性并执行必要的验证,而无需在CORS中采取繁重的浏览器端预防措施。


1这是一种简化。资源的跨域GET请求(包括<img>,<link>和<script>标记)和表单提交POST请求始终被允许作为Web的基本功能。现在,也允许其请求具有相同属性的跨域AJAX调用,这些调用称为简单跨域请求。但是,除非服务器的CORS标头明确允许,否则不允许在代码中访问此类请求返回的数据。同样,正是这些“简单”的POST请求是服务器使用反CSRF令牌保护自己免受恶意网站攻击的主要原因。

2实际上,检查报文源的安全方法甚至不可用,因为Referer标头可以被欺骗,例如使用开放重定向漏洞。这也说明了当时人们对CSRF漏洞的了解程度如何。


6
确实可以回答问题,所以+1。但是,根据记录,我强烈不同意这种推理。我预计,由于这项设计决定,使用WebSockets的大量站点将无法验证Origin标头并将私有用户数据泄露给第三方站点。客户端检查Access-Control-Allow-Origin标头就像在允许JS访问Web上对任何其他跨源HTTP请求的响应之前所做的一样,是防止整个攻击类别的一种简单方法(跨站点WebSocket劫持)。现在为时已晚。
Ajedi32 '18

3
我倾向于同意,设计更改实际上是从基于白名单的方法转变为有风险的黑名单方法。有道理。
staafl

42

奥伯斯特回答了这个问题。谢谢!不幸的是,我无法将其标记为“正确”,因为它是注释。浏览器发送可以由应用程序检查的“来源”标头。

在Java [1]中:

@Override
公共无效onOpen(WebSocket clientSocket,ClientHandshake握手){
    字符串clientOrigin = handshake.getFieldValue(“ origin”);

    如果(clientOrigin == null ||!clientOrigin.equals(WEBSOCKET_ALLOWED_ORIGIN_HEADER)){
        logger.log(Level.WARNING,“客户端未发送正确的原始标头:” + clientOrigin);        

        clientSocket.close();
        返回;
    }

    // ...
}

[1]使用https://github.com/TooTallNate/Java-WebSocket


OWASP提到检查其CSRF备忘单中的Origin(和潜在的Referer)标头是第一步,也是最重要的一步,但他们也建议更进一步并实现CSRF专用防御。对于WebSocket,这可能是将XSRF防伪令牌附加到WS URI作为查询参数,并在进行源检查后在服务器端对其进行验证。
凯文·塞克里斯特

18

WebSocket可以跨域通信,并且不受SOP(相同来源策略)的限制。

没有WebSockets,可能会发生与您描述的相同的安全问题。

邪恶的JS可以:

  • 创建一个带有指向evil.tld的URL的脚本/图像标签,然后将数据放入查询字符串中。
  • 创建一个表单标签,将数据放在字段中,然后执行可以跨域的HTTP POST来调用表单的“提交”操作。AJAX受SOP限制,但普通的HTTP POST没有限制。检查XSRF Web安全问题。

如果您的网页中注入了javascript脚本,或者您获取了恶意javascript脚本,则您的安全性已被破坏。


1
我不担心邪恶的JS。我知道这总是有可能的。我真正关心的是浏览器突破:任何网站现在都可以与本地绑定的WS套接字通信并从那里窃取数据。
binwiederhier 2014年

53
SOP / CORS不适用于WebSocket,但浏览器将发送一个origin标头,其中包含使用打开WebSocket连接的JS为HTML提供服务的服务器的主机名。然后,WebSocket服务器可以通过选中来限制访问origin
oberstet 2014年

这不能回答问题。问题是,为什么来自其他域网页 可以访问本地WebSocket。在OP方案中,没有任何东西可以“在页面中注入javascript”-这是另一种方案。没有WebSocket,远程网页将无法读取localhost上的资源,因为这正是SOP阻止的。
sleske
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.