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

bin*_*ier 74 javascript security websocket

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

我现在的问题是:
为什么这可能?浏览器中是否没有实现跨源策略(此处:Linux上的FF29)?

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

Local WebSocket Server            Browser            Evil Web Server
at ws://localhost:1234                               at http://evil.tld
        |                            |                       |
        |                            |------[GET /]--------->|
        |                            |<-----[HTML+EvilJS]----|
        |<------[connect ws://..]----|                       |
        |<----[some communication]-->|                       |
        |                            |----[evil forward]---->|
        |                            |                       |

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

bin*_*ier 39

oberstet回答了这个问题.谢谢!不幸的是,我无法将其标记为"正确",因为它是一个评论.浏览器发送"origin"标题,可由应用程序检查.

在Java [1]中:

@Override
public void onOpen(WebSocket clientSocket, ClientHandshake handshake) {
    String clientOrigin = handshake.getFieldValue("origin");

    if (clientOrigin == null || !clientOrigin.equals(WEBSOCKET_ALLOWED_ORIGIN_HEADER)) {
        logger.log(Level.WARNING, "Client did not sent correct origin header: " + clientOrigin);        

        clientSocket.close();
        return;
    }

    // ...
}

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

  • OWASP 在其 [CSRF 备忘单](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet) 中提到检查 Origin(以及可能的 Referer)标头作为第一步也是最重要的一步,但他们还建议更进一步,实施 CSRF 特定防御。对于 WebSockets,这可能是将 XSRF 防伪令牌作为查询参数附加到 WS URI,并在源检查后在服务器端对其进行验证。 (2认同)

sta*_*afl 39

解决"为什么?" 部分原因是浏览器不对WebSockets实施同源策略(其中CORS是一种放松)而不是AJAX调用,是因为WebSockets是在建立跨源请求的价值之后引入的,因为它们是'不受SOP约束,CORS客户端检查的历史原因不适用.

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

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

WebSockets是一种较新的技术,旨在从一开始就支持跨域方案.任何编写服务器逻辑的人都应该知道跨源请求的可能性并执行必要的验证,而不需要像CORS那样采用严厉的浏览器端预防措施.


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

2实际上,检查请求源的安全方法甚至不可用,因为Referer标头可能被欺骗,例如使用开放重定向漏洞.这也显示了当时对CSRF漏洞的了解程度.

  • 这确实回答了这个问题,所以+1.但是,为了记录,我强烈不同意这种推理.我预测,由于此设计决策,大量使用WebSockets的站点将无法验证"Origin"标头并因此将私有用户数据泄露给第三方站点.客户端检查`Access-Control-Allow-Origin`标头,就像允许JS访问Web上任何其他跨源HTTP请求的响应一样,这将是防止整个攻击类别的简单方法(跨站点WebSocket劫持).现在太晚了. (4认同)
  • 我倾向于同意,设计变更基本上是从基于白名单的方法转变为黑名单方式,这是有风险的.有道理. (2认同)

vto*_*ola 17

WebSockets可以跨域通信,它们不受SOP(同源策略)的限制.

您描述的相同安全问题可能在没有WebSockets的情况下发生.

邪恶的JS可以:

  • 使用指向evil.tld的URL创建脚本/图像标记,并将数据放入查询字符串中.
  • 创建表单标记,将数据放在字段中,并调用表单的"提交"操作,执行HTTP POST,可以是跨域.AJAX受SOP限制,但普通的HTTP POST不受限制.检查XSRF Web安全问题.

如果某些内容在您的页面中注入了javascript,或者您获得了恶意javascript,那么您的安全性已经被破坏.

  • SOP/CORS不适用于WebSocket,但浏览器将发送一个`origin`标头,其中包含用于打开WebSocket连接的JS服务于HTML的服务器的主机名.然后,WebSocket服务器可以通过检查"origin"来限制访问. (48认同)