Websockets 客户端 API 中的 HTTP 标头

IT技术 javascript http header websocket
2021-01-11 03:16:26

看起来很容易使用任何支持此功能的 HTTP 标头客户端将自定义 HTTP 标头添加到您的 websocket 客户端,但我找不到如何使用 JSON API 来做到这一点。

然而,似乎应该在规范中支持这些标头

任何人都知道如何实现它?

var ws = new WebSocket("ws://example.com/service");

具体来说,我需要能够发送 HTTP 授权标头。

6个回答

更新 2 倍

简短回答:不可以,只能指定路径和协议字段。

更长的答案:

JavaScript WebSockets API 中没有用于指定客户端/浏览器要发送的附加标头的方法。可以在 WebSocket 构造函数中指定 HTTP 路径(“GET /xyz”)和协议头(“Sec-WebSocket-Protocol”)。

Sec-WebSocket-Protocol 标头(有时会扩展以用于特定于 websocket 的身份验证)是从 WebSocket 构造函数的可选第二个参数生成的:

var ws = new WebSocket("ws://example.com/path", "protocol");
var ws = new WebSocket("ws://example.com/path", ["protocol1", "protocol2"]);

以上结果导致以下标题:

Sec-WebSocket-Protocol: protocol

Sec-WebSocket-Protocol: protocol1, protocol2

实现 WebSocket 身份验证/授权的常见模式是实现票务系统,其中托管 WebSocket 客户端的页面从服务器请求票证,然后在 WebSocket 连接建立期间通过 URL/查询字符串、协议字段中的票证,或需要作为连接建立后的第一条消息。然后,如果票证有效(存在、尚未使用、票证中编码的客户端 IP 匹配、票证中的时间戳是最近的等),服务器仅允许连接继续。以下是 WebSocket 安全信息的摘要:https : //devcenter.heroku.com/articles/websocket-security

基本身份验证以前是一个选项,但这已被弃用,即使指定了标头,现代浏览器也不会发送标头。

基本身份验证信息(已弃用 - 不再起作用)

注意:以下信息在任何现代浏览器中都不再准确。

Authorization 标头是从 WebSocket URI 的用户名和密码(或只是用户名)字段生成的:

var ws = new WebSocket("ws://username:password@example.com")

上面的结果是带有字符串“username:password”base64 编码的以下标头:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

我已经在 Chrome 55 和 Firefox 50 中测试了基本身份验证,并验证了基本身份验证信息确实是与服务器协商的(这在 Safari 中可能不起作用)。

感谢 Dmitry Frank 的基本身份验证答案

@eleotlecram,加入 HyBi 工作组并提出建议。该小组向公众开放,并且正在为协议的后续版本进行工作。
2021-03-12 03:16:26
不幸的是,这在 Edge 中似乎不起作用。谢谢,女士:/
2021-03-15 03:16:26
@Charlie:如果您完全控制服务器,那是一种选择。更常见的方法是从您的普通 HTTP 服务器生成票证/令牌,然后让客户端发送票证/令牌(作为 websocket 路径中的查询字符串或作为第一个 websocket 消息)。然后 websocket 服务器验证票证/令牌是否有效(尚未过期、尚未使用、来自与创建时相同的 IP 等)。另外,我相信大多数 websockets 客户端都支持基本身份验证(虽然可能对你来说还不够)。更多信息:devcenter.heroku.com/articles/websocket-security
2021-03-23 03:16:26
我遇到了同样的问题。太糟糕了,这些标准的集成度太差了。您可能希望他们查看 XHR API 来查找 WebSockets API 的需求(因为 WebSockets 和 XHR 是相关的),但似乎他们只是在孤岛上开发 API。
2021-03-28 03:16:26
我猜是设计使然。我的印象是该实现是有意从 HTTP 借用的,但在设计上尽可能地将它们分开。规范中的文本继续说道:“然而,该设计并未将 WebSocket 限制为 HTTP,未来的实现可以在专用端口上使用更简单的握手,而无需重新发明整个协议。最后一点很重要,因为交互消息的流量模式确实与标准 HTTP 流量不匹配,可能会导致某些组件出现异常负载。”
2021-04-04 03:16:26

更多的替代解决方案,但所有现代浏览器都将域 cookie 与连接一起发送,因此使用:

var authToken = 'R3YKZFKBVi';

document.cookie = 'X-Authorization=' + authToken + '; path=/';

var ws = new WebSocket(
    'wss://localhost:9000/wss/'
);

以请求连接头结束:

Cookie: X-Authorization=R3YKZFKBVi
Christian Schneider(上述文章的作者)建议在使用 Authentication Cookie 时使用 CSRF-Tokens 来保护初始 HTTP 握手: ws = new WebSocket("wss://example.com/wss?csrftoken=<token>")
2021-03-14 03:16:26
Websocket 请求不受同源策略的约束。将身份验证作为 cookie 发送将使您的应用程序被劫持。参见christian-schneider.net/CrossSiteWebSocketHijacking.html
2021-03-19 03:16:26
如果 WS 服务器 URI 与客户端 URI 不同怎么办?
2021-03-24 03:16:26
但是,您可以设置一个 HTTP 服务,在相关路径上设置会话 cookie,并在启动 websocket 之前调用它。调用,例如,https://example.com/login并让响应设置一个 cookie,/wss然后new WebSocket("wss://example.com/wss")将开始与相关 cookie 的握手请求。请注意,devtools 可能不会显示 cookie,但仍应发送它。
2021-04-05 03:16:26
@Danish 那么那不起作用,因为您无法为其他域客户端设置 cookie
2021-04-09 03:16:26

HTTP 授权标头问题可以通过以下方式解决:

var ws = new WebSocket("ws://username:password@example.com/service");

然后,将使用提供的username设置正确的基本授权 HTTP 标头password如果您需要基本授权,那么您就万事大吉了。


Bearer然而,我想使用,我采用了以下技巧:我按如下方式连接到服务器:

var ws = new WebSocket("ws://my_token@example.com/service");

当我在服务器端的代码收到具有非空用户名和空密码的基本授权标头时,它会将用户名解释为令牌。

这些网址的使用http://username:password@example.com已贬值。developer.mozilla.org/en-US/docs/Web/HTTP/Authentication也许这就是它不适用于 websockets 的原因!
2021-03-24 03:16:26
我和@LearnToLive 和@user9645 有同样的问题;当 URI 为该wss://user:pass@host格式时,ch​​rome 和 firefox 都不会添加授权标头这是浏览器不支持的,还是握手有问题?
2021-03-25 03:16:26
我同意@LearnToLive - 我将它与 wss 一起使用(例如wss://user:password@myhost.com/ws)并且Authorization在服务器端没有标题(使用 Chrome 60 版)
2021-03-29 03:16:26
通过 url 传输令牌是否安全?
2021-04-05 03:16:26
我正在尝试您建议的解决方案。但是我看不到将 Authorization 标头添加到我的请求中。我尝试过使用不同的浏览器,例如 Chrome V56、Firefox V51.0 我在我的本地主机上运行我的服务器。所以 websocket url 是“ws://myusername:mypassword@localhost:8080/mywebsocket”。知道可能有什么问题吗?谢谢
2021-04-06 03:16:26

发送授权标头是不可能的。

附加令牌查询参数是一个选项。但是,在某些情况下,将您的主登录令牌以纯文本形式作为查询参数发送可能是不可取的,因为它比使用标头更不透明,并且最终会被记录到任何地方。如果这给您带来了安全问题,另一种方法是将辅助 JWT 令牌仅用于 Web 套接字内容

创建用于生成此 JWT 的 REST 端点,当然只能由使用您的主要登录令牌(通过标头传输)进行身份验证的用户访问。Web 套接字 JWT 的配置可以与您的登录令牌不同,例如具有更短的超时,因此作为升级请求的查询参数发送更安全。

为在 上注册 SockJS eventbusHandler 的同一路由创建一个单独的 JwtAuthHandler确保首先注册您的身份验证处理程序,以便您可以根据您的数据库检查 Web 套接字令牌(JWT 应该以某种方式链接到后端的用户)。

这是我可以为 API Gateway websockets 提出的唯一安全解决方案。Slack 对他们的 RTM API 做了类似的事情,他们有 30 秒的超时。
2021-03-15 03:16:26
请注意,如果您从 node-js(而不是浏览器)创建 websocket 连接,则可以发送授权标头。见这里:github.com/apollographql/apollo-client/issues/...
2021-04-01 03:16:26

当您想使用 JavaScript WebSockets API 建立 WebSockets 连接时,您不能发送自定义标头。您可以Subprotocols通过使用第二个 WebSocket 类构造函数来使用标头:

var ws = new WebSocket("ws://example.com/service", "soap");

然后您可以使用Sec-WebSocket-Protocol服务器上的密钥获取子协议标头

还有一个限制,您的子协议标头值不能包含逗号 ( ,) !

我实现了这个并且它有效 - 只是感觉很奇怪。谢谢
2021-03-15 03:16:26
我不相信。JWT 由三个 base64 编码的有效负载组成,每个负载以句点分隔。我相信这排除了逗号的可能性。
2021-03-19 03:16:26
Jwt 可以包含逗号吗?
2021-03-21 03:16:26
您是建议我们使用Sec-WebSocket-Protocol标题作为标题的替代Authorization吗?
2021-03-25 03:16:26