如何保护您的WebSocket连接

The Web is growing at a massive rate. More and more web apps are dynamic, immersive and do not require the end user to refresh. There is emerging support for low latency communication technologies like websockets. Websockets allow us to achieve real-time communication among different clients connected to a server.

网络正以惊人的速度增长。 越来越多的Web应用程序是动态的,身临其境的,不需要最终用户刷新。 对低延迟通信技术(例如Websocket)的支持正在出现。 Websocket使我们能够在连接到服务器的不同客户端之间实现实时通信。

A lot of people are unaware of how to secure their websockets against some very common attacks. Let us see what they are and what should you do to protect your websockets.

许多人不知道如何保护WebSocket免受某些非常常见的攻击。 让我们看看它们是什么,以及您应该怎么做才能保护WebSocket。

0:启用CORS (0: Enable CORS)

WebSocket doesn’t come with CORS inbuilt. That being said, it means that any website can connect to any other website’s websocket connection and communicate without any restriction! I’m not going into reasons why this is the way it is, but a quick fix to this is to verify Origin header on the websocket handshake.

WebSocket没有内置的CORS。 就是说,这意味着任何网站都可以连接到任何其他网站的websocket连接并进行通信而没有任何限制! 我没有说明为什么会这样,但是对此的快速解决方案是验证websocket握手上的Origin标头。

Sure, Origin header can be faked by an attacker, but it doesn’t matter, because to exploit it, attacker needs to fake the Origin header on victim’s browser, and modern browsers do not allow normal javascript sitting in web browsers to change Origin header.

当然,攻击者可以伪造Origin标头,但这没关系,因为要利用它,攻击者需要在受害者的浏览器上伪造Origin标头,现代浏览器不允许网络浏览器中的普通javascript更改Origin标头。

Moreover, if you’re actually authenticating users using, preferably, cookies, then this is not really a problem for you (more on this on point #4)

此外,如果您实际上是在使用(最好是使用Cookie)对用户进行身份验证,那么这对您来说并不是真正的问题(有关第4点的更多信息)

1:实施速率限制 (1: Implement rate limiting)

Rate limiting is important. Without it, clients can knowingly or unknowingly perform a DoS attack on your server. DoS stands for Denial of Service. DoS means a single client is keeping the server so busy that the server is unable to handle other clients.

速率限制很重要。 没有它,客户端可以有意或无意地对您的服务器进行DoS攻击。 DoS代表拒绝服务。 DoS意味着单个客户端使服务器保持繁忙状态,以致该服务器无法处理其他客户端。

In most of the cases it is a deliberate attempt by an attacker to bring down a server. Sometimes poor frontend implementations can also lead to DoS by normal clients.

在大多数情况下,攻击者是有意尝试关闭服务器。 有时不良的前端实施也可能导致普通客户端进行DoS。

We’re gonna make use of the leaky bucket algorithm (which apparently is a very common algorithm for networks to implement) for implementing rate limiting on our websockets.

我们将使用泄漏存储桶算法(这显然是网络要实现的非常常见的算法)来对我们的Web套接字实施速率限制。

The idea is that you have a bucket which has a fixed size hole at its floor. You start putting water in it and the water goes out through the hole at the bottom. Now, if your rate of putting water into the bucket is larger than the rate of flowing out of the hole for a long time, at some point, the bucket will become full and start leaking. That’s all.

这个想法是,您有一个在地板上有固定大小Kong的水桶。 您开始向其中放水,水从底部的Kong流出。 现在,如果您长时间将水倒入桶中的速度大于从Kong中流出的速度,在某个时候,桶将变满并开始泄漏。 就这样。

Let’s now understand how it relates to our websocket:

现在,让我们了解它与websocket的关系:

  1. Water is the websocket traffic sent by the user.

    水是用户发送的网络套接字流量。
  2. Water passes down the hole. This means the server successfully processed that particular websocket request.

    水从Kong中流下来。 这意味着服务器成功处理了该特定的Websocket请求。
  3. Water which is still in the bucket and has not overflowed is basically pending traffic. The server will process this traffic later on. This could also be bursty traffic flow (i.e. too much traffic for a very small time is okay as long as bucket doesn’t leak)

    仍然在桶中并且没有溢出的水基本上是待处理的流量。 服务器稍后将处理此流量。 这也可能是突发流量(即,只要存储桶不泄漏,在很小的时间内有太多流量就可以了)
  4. Water which is overflowing is the traffic discarded by the server (too much traffic coming from a single user)

    溢出的水是服务器丢弃的流量(来自单个用户的流量太多)

The point here is, you have to check your websocket activity and determine these numbers. You’re going to assign a bucket to every user. We decide how big the bucket should be (traffic which a single user could send over a fixed period) depending on how large your hole is (how much time on average does your server need to process a single websocket request, say saving a message sent by a user into a database).

这里的重点是,您必须检查websocket活动并确定这些数字。 您将为每个用户分配一个存储桶。 我们根据您的漏洞的大小(您的服务器平均需要多少时间来处理单个websocket请求,例如保存已发送的消息)来确定存储桶的大小(单个用户可以在固定时间内发送的流量)由用户进入数据库)。

This is a trimmed down implementation I’m using at codedamn for implementing leaky bucket algorithm for the websockets. It is in NodeJS but the concept remains same.

这是我在Codedamn上使用的精简版实现,用于为websocket实现泄漏存储桶算法。 它在NodeJS中,但是概念保持不变。

if(this.limitCounter >= Socket.limit) {
  if(this.burstCounter >= Socket.burst) {
     return 'Bucket is leaking'
  }
  ++this.burstCounter
  return setTimeout(() => {
  this.verify(callingMethod, ...args)
  setTimeout(_ => --this.burstCounter, Socket.burstTime)
  }, Socket.burstDelay)
}
++this.limitCounter

So what’s happening here? Basically, if the limit is crossed as well as the burst limit (which are constants set), the websocket connection drops. Otherwise, after a particular delay, we’re gonna reset the burst counter. This leaves space again for another burst.

那么这是怎么回事? 基本上,如果超过限制和突发限制(已设置常量),则websocket连接将断开。 否则,经过特定的延迟后,我们将重置突发计数器。 这又为再次爆发留出了空间。

2:限制有效载荷大小 (2: Restrict payload size)

This should be implemented as a feature within your server-side websocket library. If not, its time to change it to a better one! You should limit the maximum length of the message that could be sent over your websocket. Theoretically there is no limit. Of course, getting a huge payload is very likely to hang that particular socket instance and eat up more system resources than required.

这应该作为服务器端Websocket库中的功能实现。 如果没有的话,就该把它变成更好的了! 您应该限制可以通过WebSocket发送的消息的最大长度。 理论上没有限制。 当然,获得巨大的负载很可能会挂起该特定的套接字实例,并消耗比所需更多的系统资源。

For example, if you’re using WS library for Node for creating websockets on server, you can use the maxPayload option to specify the maximum payload size in bytes. If the payload size is bigger than that, the library will natively drop the connection.

例如,如果您使用WS的Node库来在服务器上创建websocket,则可以使用maxPayload选项指定最大有效负载大小(以字节为单位)。 如果有效负载大小大于该大小,则库将自然断开连接。

Do not try to implement this on your own by determining message length. We don’t want to read the whole message into the system RAM first. If it is even 1 byte greater than our set limit, drop it. That could be only implemented by the library (which handles messages as a stream of bytes rather than fixed strings).

不要尝试通过确定消息长度来自行实现此目的。 我们不想先将整个消息读入系统RAM。 如果它甚至比我们设置的限制大1个字节,请将其删除。 那只能由库来实现(该库将消息作为字节流而不是固定字符串来处理)。

3:创建可靠的通信协议 (3: Create a solid communication protocol)

Because now you’re on a duplex connection, you could be sending anything to the server. The server could send any text back to client. You would need to have a way for effective communication between both.

因为现在您处于双工连接,所以您可能会将任何内容发送到服务器。 服务器可以将任何文本发送回客户端。 您将需要一种在两者之间进行有效沟通的方法。

You can’t send raw messages if you want to scale the messaging aspect of your website. I prefer using JSON, but there are other optimized ways to set up a communication. However, considering JSON, here’s what a basic messaging schema would look like for a generic site:

如果要扩展网站的消息传递方面,则不能发送原始消息。 我更喜欢使用JSON,但是还有其他优化的方式来建立通信。 但是,考虑到JSON,以下是通用站点的基本消息传递模式:

Client to Server (or vice versa): { status: "ok"|"error", event: EVENT_NAME, data: <any arbitrary data> }

Now it’s easier for you on the server to check for valid events and format. Drop the connection immediately and log the IP address of the user if the message format differs. There’s no way the format would change unless someone is manually tingling with your websocket connection. If you’re on node, I recommend using the Joi library for further validation of incoming data from user.

现在,您可以更轻松地在服务器上检查有效事件和格式。 如果消息格式不同,请立即断开连接并记录用户的IP地址。 除非有人手动对您的websocket连接进行刺痛,否则无法更改格式。 如果您在节点上,建议您使用Joi库进一步验证来自用户的传入数据。

4:在建立WS连接之前对用户进行身份验证 (4: Authenticate users before WS connection establishes)

If you’re using websockets for authenticated users, it is a pretty good idea to only allow authenticated users to establish a successful websocket connection. Don’t allow anyone to establish a connection and then wait for them to authenticate over the websocket itself. First of all, establishing a websocket connection is a bit expensive anyway. So you don’t want unauthorized people hopping on your websockets and hogging connections which could be used by other people.

如果您将Websockets用于经过身份验证的用户,则最好只允许经过身份验证的用户建立成功的Websocket连接。 不允许任何人建立连接,然后等待他们通过websocket本身进行身份验证。 首先,建立Websocket连接反正有点昂贵。 因此,您不希望未经授权的人在您的Web套接字上跳来跳去,浪费别人可能使用的连接。

To do this, when you’re establishing a connection on frontend, pass some authentication data to websocket. It could be a header like X-Auth-Token: <some token assigned to this client on login>. By default, cookies would be passed anyway.

为此,在前端上建立连接时,请将一些身份验证数据传递到websocket。 它可能是标头,例如X-Auth-Token:<登录时分配给此客户端的某些令牌>。 默认情况下,无论如何都会传递cookie。

Again, it really comes down to the library you’re using on the server for implementing websockets. But if you’re on Node and using WS, there’s this verifyClient function which gets you access to info object passed to a websocket connection. (Just like you have access to req object for HTTP requests.)

同样,它实际上取决于您在服务器上用于实现Websocket的库。 但是,如果您在Node上并使用WS,则可以使用该verifyClient函数来访问传递给websocket连接的信息对象。 (就像您可以访问HTTP请求的req对象一样。)

5:在Websocket上使用SSL (5: Use SSL over websockets)

This is a no-brainer, but still needs to be said. Use wss:// instead of ws://. This adds a security layer over your communication. Use a server like Nginx for reverse proxying websockets and enable SSL over them. Setting up Nginx would be a whole another tutorial. I’ll leave the directive you need to use for Nginx for those folks who are familiar with it. More info here.

这是理所当然的,但仍然需要说。 使用wss://而不是ws://。 这为您的通信增加了安全层。 使用Nginx之类的服务器进行反向代理Websocket,并对其启用SSL。 设置Nginx完全是另一个教程。 对于那些熟悉Nginx的人,我将保留您需要使用的指令。 更多信息在这里

location /your-websocket-location/ {
    proxy_pass ​http://127.0.0.1:1337;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
}

Here it is assumed your websocket server is listening on port 1337 and your users connect to your websocket in this fashion:

这里假设您的websocket服务器正在侦听端口1337,并且您的用户以这种方式连接到您的websocket:

const ws = new WebSocket('wss://yoursite.com/your-websocket-location')

有什么问题吗 (Questions?)

Have any questions or suggestions? Ask away!

有什么问题或建议吗? 问吧!

翻译自: https://www.freecodecamp.org/news/how-to-secure-your-websocket-connections-d0be0996c556/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值